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
},
38 Set the internal page table base address.
39 If it is non zero, further MemoryAttribute modification will be on this page table.
40 If it is zero, further MemoryAttribute modification will be on real page table.
42 @param Cr3 page table base.
53 Return page table base.
55 @return page table base.
62 if (mInternalGr3
!= 0) {
65 return (AsmReadCr3 () & PAGING_4K_ADDRESS_MASK_64
);
69 Return length according to page attributes.
71 @param[in] PageAttributes The page attribute of the page entry.
73 @return The length of page entry.
76 PageAttributeToLength (
77 IN PAGE_ATTRIBUTE PageAttribute
81 for (Index
= 0; Index
< sizeof(mPageAttributeTable
)/sizeof(mPageAttributeTable
[0]); Index
++) {
82 if (PageAttribute
== mPageAttributeTable
[Index
].Attribute
) {
83 return (UINTN
)mPageAttributeTable
[Index
].Length
;
90 Return address mask according to page attributes.
92 @param[in] PageAttributes The page attribute of the page entry.
94 @return The address mask of page entry.
98 IN PAGE_ATTRIBUTE PageAttribute
102 for (Index
= 0; Index
< sizeof(mPageAttributeTable
)/sizeof(mPageAttributeTable
[0]); Index
++) {
103 if (PageAttribute
== mPageAttributeTable
[Index
].Attribute
) {
104 return (UINTN
)mPageAttributeTable
[Index
].AddressMask
;
111 Return page table entry to match the address.
113 @param[in] Address The address to be checked.
114 @param[out] PageAttributes The page attribute of the page entry.
116 @return The page entry.
120 IN PHYSICAL_ADDRESS Address
,
121 OUT PAGE_ATTRIBUTE
*PageAttribute
133 Index4
= ((UINTN
)RShiftU64 (Address
, 39)) & PAGING_PAE_INDEX_MASK
;
134 Index3
= ((UINTN
)Address
>> 30) & PAGING_PAE_INDEX_MASK
;
135 Index2
= ((UINTN
)Address
>> 21) & PAGING_PAE_INDEX_MASK
;
136 Index1
= ((UINTN
)Address
>> 12) & PAGING_PAE_INDEX_MASK
;
138 if (sizeof(UINTN
) == sizeof(UINT64
)) {
139 L4PageTable
= (UINT64
*)GetPageTableBase ();
140 if (L4PageTable
[Index4
] == 0) {
141 *PageAttribute
= PageNone
;
145 L3PageTable
= (UINT64
*)(UINTN
)(L4PageTable
[Index4
] & ~mAddressEncMask
& PAGING_4K_ADDRESS_MASK_64
);
147 L3PageTable
= (UINT64
*)GetPageTableBase ();
149 if (L3PageTable
[Index3
] == 0) {
150 *PageAttribute
= PageNone
;
153 if ((L3PageTable
[Index3
] & IA32_PG_PS
) != 0) {
155 *PageAttribute
= Page1G
;
156 return &L3PageTable
[Index3
];
159 L2PageTable
= (UINT64
*)(UINTN
)(L3PageTable
[Index3
] & ~mAddressEncMask
& PAGING_4K_ADDRESS_MASK_64
);
160 if (L2PageTable
[Index2
] == 0) {
161 *PageAttribute
= PageNone
;
164 if ((L2PageTable
[Index2
] & IA32_PG_PS
) != 0) {
166 *PageAttribute
= Page2M
;
167 return &L2PageTable
[Index2
];
171 L1PageTable
= (UINT64
*)(UINTN
)(L2PageTable
[Index2
] & ~mAddressEncMask
& PAGING_4K_ADDRESS_MASK_64
);
172 if ((L1PageTable
[Index1
] == 0) && (Address
!= 0)) {
173 *PageAttribute
= PageNone
;
176 *PageAttribute
= Page4K
;
177 return &L1PageTable
[Index1
];
181 Return memory attributes of page entry.
183 @param[in] PageEntry The page entry.
185 @return Memory attributes of page entry.
188 GetAttributesFromPageEntry (
194 if ((*PageEntry
& IA32_PG_P
) == 0) {
195 Attributes
|= EFI_MEMORY_RP
;
197 if ((*PageEntry
& IA32_PG_RW
) == 0) {
198 Attributes
|= EFI_MEMORY_RO
;
200 if ((*PageEntry
& IA32_PG_NX
) != 0) {
201 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
;
234 if ((Attributes
& EFI_MEMORY_RO
) != 0) {
236 NewPageEntry
&= ~(UINT64
)IA32_PG_RW
;
237 if (mInternalGr3
!= 0) {
239 // ReadOnly page need set Dirty bit for shadow stack
240 NewPageEntry
|= IA32_PG_D
;
241 // Clear user bit for supervisor shadow stack
242 NewPageEntry
&= ~(UINT64
)IA32_PG_U
;
245 // Clear dirty bit for non shadow stack, to protect RO page.
246 NewPageEntry
&= ~(UINT64
)IA32_PG_D
;
249 NewPageEntry
|= IA32_PG_RW
;
252 if ((Attributes
& EFI_MEMORY_XP
) != 0) {
255 NewPageEntry
|= IA32_PG_NX
;
257 NewPageEntry
&= ~IA32_PG_NX
;
261 *PageEntry
= NewPageEntry
;
262 if (CurrentPageEntry
!= NewPageEntry
) {
264 DEBUG ((DEBUG_VERBOSE
, "ConvertPageEntryAttribute 0x%lx", CurrentPageEntry
));
265 DEBUG ((DEBUG_VERBOSE
, "->0x%lx\n", NewPageEntry
));
272 This function returns if there is need to split page entry.
274 @param[in] BaseAddress The base address to be checked.
275 @param[in] Length The length to be checked.
276 @param[in] PageEntry The page entry to be checked.
277 @param[in] PageAttribute The page attribute of the page entry.
279 @retval SplitAttributes on if there is need to split page entry.
283 IN PHYSICAL_ADDRESS BaseAddress
,
285 IN UINT64
*PageEntry
,
286 IN PAGE_ATTRIBUTE PageAttribute
289 UINT64 PageEntryLength
;
291 PageEntryLength
= PageAttributeToLength (PageAttribute
);
293 if (((BaseAddress
& (PageEntryLength
- 1)) == 0) && (Length
>= PageEntryLength
)) {
297 if (((BaseAddress
& PAGING_2M_MASK
) != 0) || (Length
< SIZE_2MB
)) {
305 This function splits one page entry to small page entries.
307 @param[in] PageEntry The page entry to be splitted.
308 @param[in] PageAttribute The page attribute of the page entry.
309 @param[in] SplitAttribute How to split the page entry.
311 @retval RETURN_SUCCESS The page entry is splitted.
312 @retval RETURN_UNSUPPORTED The page entry does not support to be splitted.
313 @retval RETURN_OUT_OF_RESOURCES No resource to split page entry.
317 IN UINT64
*PageEntry
,
318 IN PAGE_ATTRIBUTE PageAttribute
,
319 IN PAGE_ATTRIBUTE SplitAttribute
323 UINT64
*NewPageEntry
;
326 ASSERT (PageAttribute
== Page2M
|| PageAttribute
== Page1G
);
328 if (PageAttribute
== Page2M
) {
332 ASSERT (SplitAttribute
== Page4K
);
333 if (SplitAttribute
== Page4K
) {
334 NewPageEntry
= AllocatePageTableMemory (1);
335 DEBUG ((DEBUG_VERBOSE
, "Split - 0x%x\n", NewPageEntry
));
336 if (NewPageEntry
== NULL
) {
337 return RETURN_OUT_OF_RESOURCES
;
339 BaseAddress
= *PageEntry
& PAGING_2M_ADDRESS_MASK_64
;
340 for (Index
= 0; Index
< SIZE_4KB
/ sizeof(UINT64
); Index
++) {
341 NewPageEntry
[Index
] = (BaseAddress
+ SIZE_4KB
* Index
) | mAddressEncMask
| ((*PageEntry
) & PAGE_PROGATE_BITS
);
343 (*PageEntry
) = (UINT64
)(UINTN
)NewPageEntry
| mAddressEncMask
| PAGE_ATTRIBUTE_BITS
;
344 return RETURN_SUCCESS
;
346 return RETURN_UNSUPPORTED
;
348 } else if (PageAttribute
== Page1G
) {
351 // No need support 1G->4K directly, we should use 1G->2M, then 2M->4K to get more compact page table.
353 ASSERT (SplitAttribute
== Page2M
|| SplitAttribute
== Page4K
);
354 if ((SplitAttribute
== Page2M
|| SplitAttribute
== Page4K
)) {
355 NewPageEntry
= AllocatePageTableMemory (1);
356 DEBUG ((DEBUG_VERBOSE
, "Split - 0x%x\n", NewPageEntry
));
357 if (NewPageEntry
== NULL
) {
358 return RETURN_OUT_OF_RESOURCES
;
360 BaseAddress
= *PageEntry
& PAGING_1G_ADDRESS_MASK_64
;
361 for (Index
= 0; Index
< SIZE_4KB
/ sizeof(UINT64
); Index
++) {
362 NewPageEntry
[Index
] = (BaseAddress
+ SIZE_2MB
* Index
) | mAddressEncMask
| IA32_PG_PS
| ((*PageEntry
) & PAGE_PROGATE_BITS
);
364 (*PageEntry
) = (UINT64
)(UINTN
)NewPageEntry
| mAddressEncMask
| PAGE_ATTRIBUTE_BITS
;
365 return RETURN_SUCCESS
;
367 return RETURN_UNSUPPORTED
;
370 return RETURN_UNSUPPORTED
;
375 This function modifies the page attributes for the memory region specified by BaseAddress and
376 Length from their current attributes to the attributes specified by Attributes.
378 Caller should make sure BaseAddress and Length is at page boundary.
380 @param[in] BaseAddress The physical address that is the start address of a memory region.
381 @param[in] Length The size in bytes of the memory region.
382 @param[in] Attributes The bit mask of attributes to modify for the memory region.
383 @param[in] IsSet TRUE means to set attributes. FALSE means to clear attributes.
384 @param[out] IsSplitted TRUE means page table splitted. FALSE means page table not splitted.
385 @param[out] IsModified TRUE means page table modified. FALSE means page table not modified.
387 @retval RETURN_SUCCESS The attributes were modified for the memory region.
388 @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by
389 BaseAddress and Length cannot be modified.
390 @retval RETURN_INVALID_PARAMETER Length is zero.
391 Attributes specified an illegal combination of attributes that
392 cannot be set together.
393 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
394 the memory resource range.
395 @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the memory
396 resource range specified by BaseAddress and Length.
397 The bit mask of attributes is not support for the memory resource
398 range specified by BaseAddress and Length.
402 ConvertMemoryPageAttributes (
403 IN PHYSICAL_ADDRESS BaseAddress
,
405 IN UINT64 Attributes
,
407 OUT BOOLEAN
*IsSplitted
, OPTIONAL
408 OUT BOOLEAN
*IsModified OPTIONAL
412 PAGE_ATTRIBUTE PageAttribute
;
413 UINTN PageEntryLength
;
414 PAGE_ATTRIBUTE SplitAttribute
;
415 RETURN_STATUS Status
;
416 BOOLEAN IsEntryModified
;
417 EFI_PHYSICAL_ADDRESS MaximumSupportMemAddress
;
419 ASSERT (Attributes
!= 0);
420 ASSERT ((Attributes
& ~(EFI_MEMORY_RP
| EFI_MEMORY_RO
| EFI_MEMORY_XP
)) == 0);
422 ASSERT ((BaseAddress
& (SIZE_4KB
- 1)) == 0);
423 ASSERT ((Length
& (SIZE_4KB
- 1)) == 0);
426 return RETURN_INVALID_PARAMETER
;
429 MaximumSupportMemAddress
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)(LShiftU64 (1, mPhysicalAddressBits
) - 1);
430 if (BaseAddress
> MaximumSupportMemAddress
) {
431 return RETURN_UNSUPPORTED
;
433 if (Length
> MaximumSupportMemAddress
) {
434 return RETURN_UNSUPPORTED
;
436 if ((Length
!= 0) && (BaseAddress
> MaximumSupportMemAddress
- (Length
- 1))) {
437 return RETURN_UNSUPPORTED
;
440 // DEBUG ((DEBUG_ERROR, "ConvertMemoryPageAttributes(%x) - %016lx, %016lx, %02lx\n", IsSet, BaseAddress, Length, Attributes));
442 if (IsSplitted
!= NULL
) {
445 if (IsModified
!= NULL
) {
450 // Below logic is to check 2M/4K page to make sure we donot waist memory.
452 while (Length
!= 0) {
453 PageEntry
= GetPageTableEntry (BaseAddress
, &PageAttribute
);
454 if (PageEntry
== NULL
) {
455 return RETURN_UNSUPPORTED
;
457 PageEntryLength
= PageAttributeToLength (PageAttribute
);
458 SplitAttribute
= NeedSplitPage (BaseAddress
, Length
, PageEntry
, PageAttribute
);
459 if (SplitAttribute
== PageNone
) {
460 ConvertPageEntryAttribute (PageEntry
, Attributes
, IsSet
, &IsEntryModified
);
461 if (IsEntryModified
) {
462 if (IsModified
!= NULL
) {
467 // Convert success, move to next
469 BaseAddress
+= PageEntryLength
;
470 Length
-= PageEntryLength
;
472 Status
= SplitPage (PageEntry
, PageAttribute
, SplitAttribute
);
473 if (RETURN_ERROR (Status
)) {
474 return RETURN_UNSUPPORTED
;
476 if (IsSplitted
!= NULL
) {
479 if (IsModified
!= NULL
) {
483 // Just split current page
484 // Convert success in next around
489 return RETURN_SUCCESS
;
493 FlushTlb on current processor.
495 @param[in,out] Buffer Pointer to private data buffer.
499 FlushTlbOnCurrentProcessor (
507 FlushTlb for all processors.
516 FlushTlbOnCurrentProcessor (NULL
);
518 for (Index
= 0; Index
< gSmst
->NumberOfCpus
; Index
++) {
519 if (Index
!= gSmst
->CurrentlyExecutingCpu
) {
520 // Force to start up AP in blocking mode,
521 SmmBlockingStartupThisAp (FlushTlbOnCurrentProcessor
, Index
, NULL
);
522 // Do not check return status, because AP might not be present in some corner cases.
528 This function sets the attributes for the memory region specified by BaseAddress and
529 Length from their current attributes to the attributes specified by Attributes.
531 @param[in] BaseAddress The physical address that is the start address of a memory region.
532 @param[in] Length The size in bytes of the memory region.
533 @param[in] Attributes The bit mask of attributes to set for the memory region.
534 @param[out] IsSplitted TRUE means page table splitted. FALSE means page table not splitted.
536 @retval EFI_SUCCESS The attributes were set for the memory region.
537 @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
538 BaseAddress and Length cannot be modified.
539 @retval EFI_INVALID_PARAMETER Length is zero.
540 Attributes specified an illegal combination of attributes that
541 cannot be set together.
542 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
543 the memory resource range.
544 @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
545 resource range specified by BaseAddress and Length.
546 The bit mask of attributes is not support for the memory resource
547 range specified by BaseAddress and Length.
552 SmmSetMemoryAttributesEx (
553 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
555 IN UINT64 Attributes
,
556 OUT BOOLEAN
*IsSplitted OPTIONAL
562 Status
= ConvertMemoryPageAttributes (BaseAddress
, Length
, Attributes
, TRUE
, IsSplitted
, &IsModified
);
563 if (!EFI_ERROR(Status
)) {
566 // Flush TLB as last step
576 This function clears the attributes for the memory region specified by BaseAddress and
577 Length from their current attributes to the attributes specified by Attributes.
579 @param[in] BaseAddress The physical address that is the start address of a memory region.
580 @param[in] Length The size in bytes of the memory region.
581 @param[in] Attributes The bit mask of attributes to clear for the memory region.
582 @param[out] IsSplitted TRUE means page table splitted. FALSE means page table not splitted.
584 @retval EFI_SUCCESS The attributes were cleared for the memory region.
585 @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
586 BaseAddress and Length cannot be modified.
587 @retval EFI_INVALID_PARAMETER Length is zero.
588 Attributes specified an illegal combination of attributes that
589 cannot be cleared together.
590 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
591 the memory resource range.
592 @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
593 resource range specified by BaseAddress and Length.
594 The bit mask of attributes is not supported for the memory resource
595 range specified by BaseAddress and Length.
600 SmmClearMemoryAttributesEx (
601 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
603 IN UINT64 Attributes
,
604 OUT BOOLEAN
*IsSplitted OPTIONAL
610 Status
= ConvertMemoryPageAttributes (BaseAddress
, Length
, Attributes
, FALSE
, IsSplitted
, &IsModified
);
611 if (!EFI_ERROR(Status
)) {
614 // Flush TLB as last step
624 This function sets the attributes for the memory region specified by BaseAddress and
625 Length from their current attributes to the attributes specified by Attributes.
627 @param[in] BaseAddress The physical address that is the start address of a memory region.
628 @param[in] Length The size in bytes of the memory region.
629 @param[in] Attributes The bit mask of attributes to set for the memory region.
631 @retval EFI_SUCCESS The attributes were set for the memory region.
632 @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
633 BaseAddress and Length cannot be modified.
634 @retval EFI_INVALID_PARAMETER Length is zero.
635 Attributes specified an illegal combination of attributes that
636 cannot be set together.
637 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
638 the memory resource range.
639 @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
640 resource range specified by BaseAddress and Length.
641 The bit mask of attributes is not supported for the memory resource
642 range specified by BaseAddress and Length.
647 SmmSetMemoryAttributes (
648 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
653 return SmmSetMemoryAttributesEx (BaseAddress
, Length
, Attributes
, NULL
);
657 This function clears the attributes for the memory region specified by BaseAddress and
658 Length from their current attributes to the attributes specified by Attributes.
660 @param[in] BaseAddress The physical address that is the start address of a memory region.
661 @param[in] Length The size in bytes of the memory region.
662 @param[in] Attributes The bit mask of attributes to clear for the memory region.
664 @retval EFI_SUCCESS The attributes were cleared for the memory region.
665 @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
666 BaseAddress and Length cannot be modified.
667 @retval EFI_INVALID_PARAMETER Length is zero.
668 Attributes specified an illegal combination of attributes that
669 cannot be cleared together.
670 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
671 the memory resource range.
672 @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
673 resource range specified by BaseAddress and Length.
674 The bit mask of attributes is not supported for the memory resource
675 range specified by BaseAddress and Length.
680 SmmClearMemoryAttributes (
681 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
686 return SmmClearMemoryAttributesEx (BaseAddress
, Length
, Attributes
, NULL
);
690 Set ShadowStack memory.
692 @param[in] Cr3 The page table base address.
693 @param[in] BaseAddress The physical address that is the start address of a memory region.
694 @param[in] Length The size in bytes of the memory region.
696 @retval EFI_SUCCESS The shadow stack memory is set.
701 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
707 SetPageTableBase (Cr3
);
709 Status
= SmmSetMemoryAttributes (BaseAddress
, Length
, EFI_MEMORY_RO
);
711 SetPageTableBase (0);
717 Set not present memory.
719 @param[in] Cr3 The page table base address.
720 @param[in] BaseAddress The physical address that is the start address of a memory region.
721 @param[in] Length The size in bytes of the memory region.
723 @retval EFI_SUCCESS The not present memory is set.
728 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
734 SetPageTableBase (Cr3
);
736 Status
= SmmSetMemoryAttributes (BaseAddress
, Length
, EFI_MEMORY_RP
);
738 SetPageTableBase (0);
744 Retrieves a pointer to the system configuration table from the SMM System Table
745 based on a specified GUID.
747 @param[in] TableGuid The pointer to table's GUID type.
748 @param[out] Table The pointer to the table associated with TableGuid in the EFI System Table.
750 @retval EFI_SUCCESS A configuration table matching TableGuid was found.
751 @retval EFI_NOT_FOUND A configuration table matching TableGuid could not be found.
756 SmmGetSystemConfigurationTable (
757 IN EFI_GUID
*TableGuid
,
763 ASSERT (TableGuid
!= NULL
);
764 ASSERT (Table
!= NULL
);
767 for (Index
= 0; Index
< gSmst
->NumberOfTableEntries
; Index
++) {
768 if (CompareGuid (TableGuid
, &(gSmst
->SmmConfigurationTable
[Index
].VendorGuid
))) {
769 *Table
= gSmst
->SmmConfigurationTable
[Index
].VendorTable
;
774 return EFI_NOT_FOUND
;
778 This function sets SMM save state buffer to be RW and XP.
781 PatchSmmSaveStateMap (
790 TileCodeSize
= GetSmiHandlerSize ();
791 TileCodeSize
= ALIGN_VALUE(TileCodeSize
, SIZE_4KB
);
792 TileDataSize
= (SMRAM_SAVE_STATE_MAP_OFFSET
- SMM_PSD_OFFSET
) + sizeof (SMRAM_SAVE_STATE_MAP
);
793 TileDataSize
= ALIGN_VALUE(TileDataSize
, SIZE_4KB
);
794 TileSize
= TileDataSize
+ TileCodeSize
- 1;
795 TileSize
= 2 * GetPowerOfTwo32 ((UINT32
)TileSize
);
797 DEBUG ((DEBUG_INFO
, "PatchSmmSaveStateMap:\n"));
798 for (Index
= 0; Index
< mMaxNumberOfCpus
- 1; Index
++) {
802 SmmSetMemoryAttributes (
803 mCpuHotPlugData
.SmBase
[Index
] + SMM_HANDLER_OFFSET
,
807 SmmClearMemoryAttributes (
808 mCpuHotPlugData
.SmBase
[Index
] + SMM_HANDLER_OFFSET
,
816 SmmClearMemoryAttributes (
817 mCpuHotPlugData
.SmBase
[Index
] + SMM_HANDLER_OFFSET
+ TileCodeSize
,
818 TileSize
- TileCodeSize
,
821 SmmSetMemoryAttributes (
822 mCpuHotPlugData
.SmBase
[Index
] + SMM_HANDLER_OFFSET
+ TileCodeSize
,
823 TileSize
- TileCodeSize
,
831 SmmSetMemoryAttributes (
832 mCpuHotPlugData
.SmBase
[mMaxNumberOfCpus
- 1] + SMM_HANDLER_OFFSET
,
836 SmmClearMemoryAttributes (
837 mCpuHotPlugData
.SmBase
[mMaxNumberOfCpus
- 1] + SMM_HANDLER_OFFSET
,
845 SmmClearMemoryAttributes (
846 mCpuHotPlugData
.SmBase
[mMaxNumberOfCpus
- 1] + SMM_HANDLER_OFFSET
+ TileCodeSize
,
847 SIZE_32KB
- TileCodeSize
,
850 SmmSetMemoryAttributes (
851 mCpuHotPlugData
.SmBase
[mMaxNumberOfCpus
- 1] + SMM_HANDLER_OFFSET
+ TileCodeSize
,
852 SIZE_32KB
- TileCodeSize
,
858 This function sets GDT/IDT buffer to be RO and XP.
865 EFI_PHYSICAL_ADDRESS BaseAddress
;
871 DEBUG ((DEBUG_INFO
, "PatchGdtIdtMap - GDT:\n"));
873 BaseAddress
= mGdtBuffer
;
874 Size
= ALIGN_VALUE(mGdtBufferSize
, SIZE_4KB
);
876 // The range should have been set to RO
877 // if it is allocated with EfiRuntimeServicesCode.
879 SmmSetMemoryAttributes (
888 DEBUG ((DEBUG_INFO
, "PatchGdtIdtMap - IDT:\n"));
890 BaseAddress
= gcSmiIdtr
.Base
;
891 Size
= ALIGN_VALUE(gcSmiIdtr
.Limit
+ 1, SIZE_4KB
);
893 // The range should have been set to RO
894 // if it is allocated with EfiRuntimeServicesCode.
896 SmmSetMemoryAttributes (
904 This function sets memory attribute according to MemoryAttributesTable.
907 SetMemMapAttributes (
911 EFI_MEMORY_DESCRIPTOR
*MemoryMap
;
912 EFI_MEMORY_DESCRIPTOR
*MemoryMapStart
;
913 UINTN MemoryMapEntryCount
;
914 UINTN DescriptorSize
;
916 EDKII_PI_SMM_MEMORY_ATTRIBUTES_TABLE
*MemoryAttributesTable
;
918 SmmGetSystemConfigurationTable (&gEdkiiPiSmmMemoryAttributesTableGuid
, (VOID
**)&MemoryAttributesTable
);
919 if (MemoryAttributesTable
== NULL
) {
920 DEBUG ((DEBUG_INFO
, "MemoryAttributesTable - NULL\n"));
924 DEBUG ((DEBUG_INFO
, "MemoryAttributesTable:\n"));
925 DEBUG ((DEBUG_INFO
, " Version - 0x%08x\n", MemoryAttributesTable
->Version
));
926 DEBUG ((DEBUG_INFO
, " NumberOfEntries - 0x%08x\n", MemoryAttributesTable
->NumberOfEntries
));
927 DEBUG ((DEBUG_INFO
, " DescriptorSize - 0x%08x\n", MemoryAttributesTable
->DescriptorSize
));
929 MemoryMapEntryCount
= MemoryAttributesTable
->NumberOfEntries
;
930 DescriptorSize
= MemoryAttributesTable
->DescriptorSize
;
931 MemoryMapStart
= (EFI_MEMORY_DESCRIPTOR
*)(MemoryAttributesTable
+ 1);
932 MemoryMap
= MemoryMapStart
;
933 for (Index
= 0; Index
< MemoryMapEntryCount
; Index
++) {
934 DEBUG ((DEBUG_INFO
, "Entry (0x%x)\n", MemoryMap
));
935 DEBUG ((DEBUG_INFO
, " Type - 0x%x\n", MemoryMap
->Type
));
936 DEBUG ((DEBUG_INFO
, " PhysicalStart - 0x%016lx\n", MemoryMap
->PhysicalStart
));
937 DEBUG ((DEBUG_INFO
, " VirtualStart - 0x%016lx\n", MemoryMap
->VirtualStart
));
938 DEBUG ((DEBUG_INFO
, " NumberOfPages - 0x%016lx\n", MemoryMap
->NumberOfPages
));
939 DEBUG ((DEBUG_INFO
, " Attribute - 0x%016lx\n", MemoryMap
->Attribute
));
940 MemoryMap
= NEXT_MEMORY_DESCRIPTOR(MemoryMap
, DescriptorSize
);
943 MemoryMap
= MemoryMapStart
;
944 for (Index
= 0; Index
< MemoryMapEntryCount
; Index
++) {
945 DEBUG ((DEBUG_VERBOSE
, "SetAttribute: Memory Entry - 0x%lx, 0x%x\n", MemoryMap
->PhysicalStart
, MemoryMap
->NumberOfPages
));
946 switch (MemoryMap
->Type
) {
947 case EfiRuntimeServicesCode
:
948 SmmSetMemoryAttributes (
949 MemoryMap
->PhysicalStart
,
950 EFI_PAGES_TO_SIZE((UINTN
)MemoryMap
->NumberOfPages
),
954 case EfiRuntimeServicesData
:
955 SmmSetMemoryAttributes (
956 MemoryMap
->PhysicalStart
,
957 EFI_PAGES_TO_SIZE((UINTN
)MemoryMap
->NumberOfPages
),
962 SmmSetMemoryAttributes (
963 MemoryMap
->PhysicalStart
,
964 EFI_PAGES_TO_SIZE((UINTN
)MemoryMap
->NumberOfPages
),
969 MemoryMap
= NEXT_MEMORY_DESCRIPTOR(MemoryMap
, DescriptorSize
);
972 PatchSmmSaveStateMap ();
979 Sort memory map entries based upon PhysicalStart, from low to high.
981 @param MemoryMap A pointer to the buffer in which firmware places
982 the current memory map.
983 @param MemoryMapSize Size, in bytes, of the MemoryMap buffer.
984 @param DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
989 IN OUT EFI_MEMORY_DESCRIPTOR
*MemoryMap
,
990 IN UINTN MemoryMapSize
,
991 IN UINTN DescriptorSize
994 EFI_MEMORY_DESCRIPTOR
*MemoryMapEntry
;
995 EFI_MEMORY_DESCRIPTOR
*NextMemoryMapEntry
;
996 EFI_MEMORY_DESCRIPTOR
*MemoryMapEnd
;
997 EFI_MEMORY_DESCRIPTOR TempMemoryMap
;
999 MemoryMapEntry
= MemoryMap
;
1000 NextMemoryMapEntry
= NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry
, DescriptorSize
);
1001 MemoryMapEnd
= (EFI_MEMORY_DESCRIPTOR
*) ((UINT8
*) MemoryMap
+ MemoryMapSize
);
1002 while (MemoryMapEntry
< MemoryMapEnd
) {
1003 while (NextMemoryMapEntry
< MemoryMapEnd
) {
1004 if (MemoryMapEntry
->PhysicalStart
> NextMemoryMapEntry
->PhysicalStart
) {
1005 CopyMem (&TempMemoryMap
, MemoryMapEntry
, sizeof(EFI_MEMORY_DESCRIPTOR
));
1006 CopyMem (MemoryMapEntry
, NextMemoryMapEntry
, sizeof(EFI_MEMORY_DESCRIPTOR
));
1007 CopyMem (NextMemoryMapEntry
, &TempMemoryMap
, sizeof(EFI_MEMORY_DESCRIPTOR
));
1010 NextMemoryMapEntry
= NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry
, DescriptorSize
);
1013 MemoryMapEntry
= NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry
, DescriptorSize
);
1014 NextMemoryMapEntry
= NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry
, DescriptorSize
);
1019 Return if a UEFI memory page should be marked as not present in SMM page table.
1020 If the memory map entries type is
1021 EfiLoaderCode/Data, EfiBootServicesCode/Data, EfiConventionalMemory,
1022 EfiUnusableMemory, EfiACPIReclaimMemory, return TRUE.
1025 @param[in] MemoryMap A pointer to the memory descriptor.
1027 @return TRUE The memory described will be marked as not present in SMM page table.
1028 @return FALSE The memory described will not be marked as not present in SMM page table.
1031 IsUefiPageNotPresent (
1032 IN EFI_MEMORY_DESCRIPTOR
*MemoryMap
1035 switch (MemoryMap
->Type
) {
1038 case EfiBootServicesCode
:
1039 case EfiBootServicesData
:
1040 case EfiConventionalMemory
:
1041 case EfiUnusableMemory
:
1042 case EfiACPIReclaimMemory
:
1050 Merge continous memory map entries whose type is
1051 EfiLoaderCode/Data, EfiBootServicesCode/Data, EfiConventionalMemory,
1052 EfiUnusableMemory, EfiACPIReclaimMemory, because the memory described by
1053 these entries will be set as NOT present in SMM page table.
1055 @param[in, out] MemoryMap A pointer to the buffer in which firmware places
1056 the current memory map.
1057 @param[in, out] MemoryMapSize A pointer to the size, in bytes, of the
1058 MemoryMap buffer. On input, this is the size of
1059 the current memory map. On output,
1060 it is the size of new memory map after merge.
1061 @param[in] DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
1065 MergeMemoryMapForNotPresentEntry (
1066 IN OUT EFI_MEMORY_DESCRIPTOR
*MemoryMap
,
1067 IN OUT UINTN
*MemoryMapSize
,
1068 IN UINTN DescriptorSize
1071 EFI_MEMORY_DESCRIPTOR
*MemoryMapEntry
;
1072 EFI_MEMORY_DESCRIPTOR
*MemoryMapEnd
;
1073 UINT64 MemoryBlockLength
;
1074 EFI_MEMORY_DESCRIPTOR
*NewMemoryMapEntry
;
1075 EFI_MEMORY_DESCRIPTOR
*NextMemoryMapEntry
;
1077 MemoryMapEntry
= MemoryMap
;
1078 NewMemoryMapEntry
= MemoryMap
;
1079 MemoryMapEnd
= (EFI_MEMORY_DESCRIPTOR
*) ((UINT8
*) MemoryMap
+ *MemoryMapSize
);
1080 while ((UINTN
)MemoryMapEntry
< (UINTN
)MemoryMapEnd
) {
1081 CopyMem (NewMemoryMapEntry
, MemoryMapEntry
, sizeof(EFI_MEMORY_DESCRIPTOR
));
1082 NextMemoryMapEntry
= NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry
, DescriptorSize
);
1085 MemoryBlockLength
= (UINT64
) (EFI_PAGES_TO_SIZE((UINTN
)MemoryMapEntry
->NumberOfPages
));
1086 if (((UINTN
)NextMemoryMapEntry
< (UINTN
)MemoryMapEnd
) &&
1087 IsUefiPageNotPresent(MemoryMapEntry
) && IsUefiPageNotPresent(NextMemoryMapEntry
) &&
1088 ((MemoryMapEntry
->PhysicalStart
+ MemoryBlockLength
) == NextMemoryMapEntry
->PhysicalStart
)) {
1089 MemoryMapEntry
->NumberOfPages
+= NextMemoryMapEntry
->NumberOfPages
;
1090 if (NewMemoryMapEntry
!= MemoryMapEntry
) {
1091 NewMemoryMapEntry
->NumberOfPages
+= NextMemoryMapEntry
->NumberOfPages
;
1094 NextMemoryMapEntry
= NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry
, DescriptorSize
);
1097 MemoryMapEntry
= PREVIOUS_MEMORY_DESCRIPTOR (NextMemoryMapEntry
, DescriptorSize
);
1102 MemoryMapEntry
= NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry
, DescriptorSize
);
1103 NewMemoryMapEntry
= NEXT_MEMORY_DESCRIPTOR (NewMemoryMapEntry
, DescriptorSize
);
1106 *MemoryMapSize
= (UINTN
)NewMemoryMapEntry
- (UINTN
)MemoryMap
;
1112 This function caches the GCD memory map information.
1119 UINTN NumberOfDescriptors
;
1120 EFI_GCD_MEMORY_SPACE_DESCRIPTOR
*MemSpaceMap
;
1124 Status
= gDS
->GetMemorySpaceMap (&NumberOfDescriptors
, &MemSpaceMap
);
1125 if (EFI_ERROR (Status
)) {
1129 mGcdMemNumberOfDesc
= 0;
1130 for (Index
= 0; Index
< NumberOfDescriptors
; Index
++) {
1131 if (MemSpaceMap
[Index
].GcdMemoryType
== EfiGcdMemoryTypeReserved
&&
1132 (MemSpaceMap
[Index
].Capabilities
& (EFI_MEMORY_PRESENT
| EFI_MEMORY_INITIALIZED
| EFI_MEMORY_TESTED
)) ==
1133 (EFI_MEMORY_PRESENT
| EFI_MEMORY_INITIALIZED
)
1135 mGcdMemNumberOfDesc
++;
1139 mGcdMemSpace
= AllocateZeroPool (mGcdMemNumberOfDesc
* sizeof (EFI_GCD_MEMORY_SPACE_DESCRIPTOR
));
1140 ASSERT (mGcdMemSpace
!= NULL
);
1141 if (mGcdMemSpace
== NULL
) {
1142 mGcdMemNumberOfDesc
= 0;
1143 gBS
->FreePool (MemSpaceMap
);
1147 mGcdMemNumberOfDesc
= 0;
1148 for (Index
= 0; Index
< NumberOfDescriptors
; Index
++) {
1149 if (MemSpaceMap
[Index
].GcdMemoryType
== EfiGcdMemoryTypeReserved
&&
1150 (MemSpaceMap
[Index
].Capabilities
& (EFI_MEMORY_PRESENT
| EFI_MEMORY_INITIALIZED
| EFI_MEMORY_TESTED
)) ==
1151 (EFI_MEMORY_PRESENT
| EFI_MEMORY_INITIALIZED
)
1154 &mGcdMemSpace
[mGcdMemNumberOfDesc
],
1155 &MemSpaceMap
[Index
],
1156 sizeof(EFI_GCD_MEMORY_SPACE_DESCRIPTOR
)
1158 mGcdMemNumberOfDesc
++;
1162 gBS
->FreePool (MemSpaceMap
);
1166 Get UEFI MemoryAttributesTable.
1169 GetUefiMemoryAttributesTable (
1174 EFI_MEMORY_ATTRIBUTES_TABLE
*MemoryAttributesTable
;
1175 UINTN MemoryAttributesTableSize
;
1177 Status
= EfiGetSystemConfigurationTable (&gEfiMemoryAttributesTableGuid
, (VOID
**)&MemoryAttributesTable
);
1178 if (!EFI_ERROR (Status
) && (MemoryAttributesTable
!= NULL
)) {
1179 MemoryAttributesTableSize
= sizeof(EFI_MEMORY_ATTRIBUTES_TABLE
) + MemoryAttributesTable
->DescriptorSize
* MemoryAttributesTable
->NumberOfEntries
;
1180 mUefiMemoryAttributesTable
= AllocateCopyPool (MemoryAttributesTableSize
, MemoryAttributesTable
);
1181 ASSERT (mUefiMemoryAttributesTable
!= NULL
);
1186 This function caches the UEFI memory map information.
1195 UINT32 DescriptorVersion
;
1196 EFI_MEMORY_DESCRIPTOR
*MemoryMap
;
1197 UINTN UefiMemoryMapSize
;
1199 DEBUG ((DEBUG_INFO
, "GetUefiMemoryMap\n"));
1201 UefiMemoryMapSize
= 0;
1203 Status
= gBS
->GetMemoryMap (
1207 &mUefiDescriptorSize
,
1210 ASSERT (Status
== EFI_BUFFER_TOO_SMALL
);
1213 Status
= gBS
->AllocatePool (EfiBootServicesData
, UefiMemoryMapSize
, (VOID
**)&MemoryMap
);
1214 ASSERT (MemoryMap
!= NULL
);
1215 if (MemoryMap
== NULL
) {
1219 Status
= gBS
->GetMemoryMap (
1223 &mUefiDescriptorSize
,
1226 if (EFI_ERROR (Status
)) {
1227 gBS
->FreePool (MemoryMap
);
1230 } while (Status
== EFI_BUFFER_TOO_SMALL
);
1232 if (MemoryMap
== NULL
) {
1236 SortMemoryMap (MemoryMap
, UefiMemoryMapSize
, mUefiDescriptorSize
);
1237 MergeMemoryMapForNotPresentEntry (MemoryMap
, &UefiMemoryMapSize
, mUefiDescriptorSize
);
1239 mUefiMemoryMapSize
= UefiMemoryMapSize
;
1240 mUefiMemoryMap
= AllocateCopyPool (UefiMemoryMapSize
, MemoryMap
);
1241 ASSERT (mUefiMemoryMap
!= NULL
);
1243 gBS
->FreePool (MemoryMap
);
1246 // Get additional information from GCD memory map.
1251 // Get UEFI memory attributes table.
1253 GetUefiMemoryAttributesTable ();
1257 This function sets UEFI memory attribute according to UEFI memory map.
1259 The normal memory region is marked as not present, such as
1260 EfiLoaderCode/Data, EfiBootServicesCode/Data, EfiConventionalMemory,
1261 EfiUnusableMemory, EfiACPIReclaimMemory.
1264 SetUefiMemMapAttributes (
1269 EFI_MEMORY_DESCRIPTOR
*MemoryMap
;
1270 UINTN MemoryMapEntryCount
;
1272 EFI_MEMORY_DESCRIPTOR
*Entry
;
1274 DEBUG ((DEBUG_INFO
, "SetUefiMemMapAttributes\n"));
1276 if (mUefiMemoryMap
!= NULL
) {
1277 MemoryMapEntryCount
= mUefiMemoryMapSize
/mUefiDescriptorSize
;
1278 MemoryMap
= mUefiMemoryMap
;
1279 for (Index
= 0; Index
< MemoryMapEntryCount
; Index
++) {
1280 if (IsUefiPageNotPresent(MemoryMap
)) {
1281 Status
= SmmSetMemoryAttributes (
1282 MemoryMap
->PhysicalStart
,
1283 EFI_PAGES_TO_SIZE((UINTN
)MemoryMap
->NumberOfPages
),
1288 "UefiMemory protection: 0x%lx - 0x%lx %r\n",
1289 MemoryMap
->PhysicalStart
,
1290 MemoryMap
->PhysicalStart
+ (UINT64
)EFI_PAGES_TO_SIZE((UINTN
)MemoryMap
->NumberOfPages
),
1294 MemoryMap
= NEXT_MEMORY_DESCRIPTOR(MemoryMap
, mUefiDescriptorSize
);
1298 // Do not free mUefiMemoryMap, it will be checked in IsSmmCommBufferForbiddenAddress().
1302 // Set untested memory as not present.
1304 if (mGcdMemSpace
!= NULL
) {
1305 for (Index
= 0; Index
< mGcdMemNumberOfDesc
; Index
++) {
1306 Status
= SmmSetMemoryAttributes (
1307 mGcdMemSpace
[Index
].BaseAddress
,
1308 mGcdMemSpace
[Index
].Length
,
1313 "GcdMemory protection: 0x%lx - 0x%lx %r\n",
1314 mGcdMemSpace
[Index
].BaseAddress
,
1315 mGcdMemSpace
[Index
].BaseAddress
+ mGcdMemSpace
[Index
].Length
,
1321 // Do not free mGcdMemSpace, it will be checked in IsSmmCommBufferForbiddenAddress().
1325 // Set UEFI runtime memory with EFI_MEMORY_RO as not present.
1327 if (mUefiMemoryAttributesTable
!= NULL
) {
1328 Entry
= (EFI_MEMORY_DESCRIPTOR
*)(mUefiMemoryAttributesTable
+ 1);
1329 for (Index
= 0; Index
< mUefiMemoryAttributesTable
->NumberOfEntries
; Index
++) {
1330 if (Entry
->Type
== EfiRuntimeServicesCode
|| Entry
->Type
== EfiRuntimeServicesData
) {
1331 if ((Entry
->Attribute
& EFI_MEMORY_RO
) != 0) {
1332 Status
= SmmSetMemoryAttributes (
1333 Entry
->PhysicalStart
,
1334 EFI_PAGES_TO_SIZE((UINTN
)Entry
->NumberOfPages
),
1339 "UefiMemoryAttribute protection: 0x%lx - 0x%lx %r\n",
1340 Entry
->PhysicalStart
,
1341 Entry
->PhysicalStart
+ (UINT64
)EFI_PAGES_TO_SIZE((UINTN
)Entry
->NumberOfPages
),
1346 Entry
= NEXT_MEMORY_DESCRIPTOR (Entry
, mUefiMemoryAttributesTable
->DescriptorSize
);
1350 // Do not free mUefiMemoryAttributesTable, it will be checked in IsSmmCommBufferForbiddenAddress().
1355 Return if the Address is forbidden as SMM communication buffer.
1357 @param[in] Address the address to be checked
1359 @return TRUE The address is forbidden as SMM communication buffer.
1360 @return FALSE The address is allowed as SMM communication buffer.
1363 IsSmmCommBufferForbiddenAddress (
1367 EFI_MEMORY_DESCRIPTOR
*MemoryMap
;
1368 UINTN MemoryMapEntryCount
;
1370 EFI_MEMORY_DESCRIPTOR
*Entry
;
1372 if (mUefiMemoryMap
!= NULL
) {
1373 MemoryMap
= mUefiMemoryMap
;
1374 MemoryMapEntryCount
= mUefiMemoryMapSize
/mUefiDescriptorSize
;
1375 for (Index
= 0; Index
< MemoryMapEntryCount
; Index
++) {
1376 if (IsUefiPageNotPresent (MemoryMap
)) {
1377 if ((Address
>= MemoryMap
->PhysicalStart
) &&
1378 (Address
< MemoryMap
->PhysicalStart
+ EFI_PAGES_TO_SIZE((UINTN
)MemoryMap
->NumberOfPages
)) ) {
1382 MemoryMap
= NEXT_MEMORY_DESCRIPTOR(MemoryMap
, mUefiDescriptorSize
);
1386 if (mGcdMemSpace
!= NULL
) {
1387 for (Index
= 0; Index
< mGcdMemNumberOfDesc
; Index
++) {
1388 if ((Address
>= mGcdMemSpace
[Index
].BaseAddress
) &&
1389 (Address
< mGcdMemSpace
[Index
].BaseAddress
+ mGcdMemSpace
[Index
].Length
) ) {
1395 if (mUefiMemoryAttributesTable
!= NULL
) {
1396 Entry
= (EFI_MEMORY_DESCRIPTOR
*)(mUefiMemoryAttributesTable
+ 1);
1397 for (Index
= 0; Index
< mUefiMemoryAttributesTable
->NumberOfEntries
; Index
++) {
1398 if (Entry
->Type
== EfiRuntimeServicesCode
|| Entry
->Type
== EfiRuntimeServicesData
) {
1399 if ((Entry
->Attribute
& EFI_MEMORY_RO
) != 0) {
1400 if ((Address
>= Entry
->PhysicalStart
) &&
1401 (Address
< Entry
->PhysicalStart
+ LShiftU64 (Entry
->NumberOfPages
, EFI_PAGE_SHIFT
))) {
1404 Entry
= NEXT_MEMORY_DESCRIPTOR (Entry
, mUefiMemoryAttributesTable
->DescriptorSize
);
1413 This function set given attributes of the memory region specified by
1414 BaseAddress and Length.
1416 @param This The EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL instance.
1417 @param BaseAddress The physical address that is the start address of
1419 @param Length The size in bytes of the memory region.
1420 @param Attributes The bit mask of attributes to set for the memory
1423 @retval EFI_SUCCESS The attributes were set for the memory region.
1424 @retval EFI_INVALID_PARAMETER Length is zero.
1425 Attributes specified an illegal combination of
1426 attributes that cannot be set together.
1427 @retval EFI_UNSUPPORTED The processor does not support one or more
1428 bytes of the memory resource range specified
1429 by BaseAddress and Length.
1430 The bit mask of attributes is not supported for
1431 the memory resource range specified by
1432 BaseAddress and Length.
1437 EdkiiSmmSetMemoryAttributes (
1438 IN EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL
*This
,
1439 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
1441 IN UINT64 Attributes
1444 return SmmSetMemoryAttributes (BaseAddress
, Length
, Attributes
);
1448 This function clears given attributes of the memory region specified by
1449 BaseAddress and Length.
1451 @param This The EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL instance.
1452 @param BaseAddress The physical address that is the start address of
1454 @param Length The size in bytes of the memory region.
1455 @param Attributes The bit mask of attributes to clear for the memory
1458 @retval EFI_SUCCESS The attributes were cleared for the memory region.
1459 @retval EFI_INVALID_PARAMETER Length is zero.
1460 Attributes specified an illegal combination of
1461 attributes that cannot be cleared together.
1462 @retval EFI_UNSUPPORTED The processor does not support one or more
1463 bytes of the memory resource range specified
1464 by BaseAddress and Length.
1465 The bit mask of attributes is not supported for
1466 the memory resource range specified by
1467 BaseAddress and Length.
1472 EdkiiSmmClearMemoryAttributes (
1473 IN EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL
*This
,
1474 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
1476 IN UINT64 Attributes
1479 return SmmClearMemoryAttributes (BaseAddress
, Length
, Attributes
);
1483 This function retrieves the attributes of the memory region specified by
1484 BaseAddress and Length. If different attributes are got from different part
1485 of the memory region, EFI_NO_MAPPING will be returned.
1487 @param This The EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL instance.
1488 @param BaseAddress The physical address that is the start address of
1490 @param Length The size in bytes of the memory region.
1491 @param Attributes Pointer to attributes returned.
1493 @retval EFI_SUCCESS The attributes got for the memory region.
1494 @retval EFI_INVALID_PARAMETER Length is zero.
1496 @retval EFI_NO_MAPPING Attributes are not consistent cross the memory
1498 @retval EFI_UNSUPPORTED The processor does not support one or more
1499 bytes of the memory resource range specified
1500 by BaseAddress and Length.
1505 EdkiiSmmGetMemoryAttributes (
1506 IN EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL
*This
,
1507 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
1509 OUT UINT64
*Attributes
1512 EFI_PHYSICAL_ADDRESS Address
;
1515 PAGE_ATTRIBUTE PageAttr
;
1518 if (Length
< SIZE_4KB
|| Attributes
== NULL
) {
1519 return EFI_INVALID_PARAMETER
;
1522 Size
= (INT64
)Length
;
1523 MemAttr
= (UINT64
)-1;
1527 PageEntry
= GetPageTableEntry (BaseAddress
, &PageAttr
);
1528 if (PageEntry
== NULL
|| PageAttr
== PageNone
) {
1529 return EFI_UNSUPPORTED
;
1533 // If the memory range is cross page table boundary, make sure they
1534 // share the same attribute. Return EFI_NO_MAPPING if not.
1536 *Attributes
= GetAttributesFromPageEntry (PageEntry
);
1537 if (MemAttr
!= (UINT64
)-1 && *Attributes
!= MemAttr
) {
1538 return EFI_NO_MAPPING
;
1543 Address
= *PageEntry
& ~mAddressEncMask
& PAGING_4K_ADDRESS_MASK_64
;
1544 Size
-= (SIZE_4KB
- (BaseAddress
- Address
));
1545 BaseAddress
+= (SIZE_4KB
- (BaseAddress
- Address
));
1549 Address
= *PageEntry
& ~mAddressEncMask
& PAGING_2M_ADDRESS_MASK_64
;
1550 Size
-= SIZE_2MB
- (BaseAddress
- Address
);
1551 BaseAddress
+= SIZE_2MB
- (BaseAddress
- Address
);
1555 Address
= *PageEntry
& ~mAddressEncMask
& PAGING_1G_ADDRESS_MASK_64
;
1556 Size
-= SIZE_1GB
- (BaseAddress
- Address
);
1557 BaseAddress
+= SIZE_1GB
- (BaseAddress
- Address
);
1561 return EFI_UNSUPPORTED
;
1564 MemAttr
= *Attributes
;