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 length according to page attributes.
55 @param[in] PageAttributes The page attribute of the page entry.
57 @return The length of page entry.
60 PageAttributeToLength (
61 IN PAGE_ATTRIBUTE PageAttribute
66 for (Index
= 0; Index
< sizeof (mPageAttributeTable
)/sizeof (mPageAttributeTable
[0]); Index
++) {
67 if (PageAttribute
== mPageAttributeTable
[Index
].Attribute
) {
68 return (UINTN
)mPageAttributeTable
[Index
].Length
;
76 Return address mask according to page attributes.
78 @param[in] PageAttributes The page attribute of the page entry.
80 @return The address mask of page entry.
84 IN PAGE_ATTRIBUTE PageAttribute
89 for (Index
= 0; Index
< sizeof (mPageAttributeTable
)/sizeof (mPageAttributeTable
[0]); Index
++) {
90 if (PageAttribute
== mPageAttributeTable
[Index
].Attribute
) {
91 return (UINTN
)mPageAttributeTable
[Index
].AddressMask
;
99 Return page table entry to match the address.
101 @param[in] Address The address to be checked.
102 @param[out] PageAttributes The page attribute of the page entry.
104 @return The page entry.
108 IN PHYSICAL_ADDRESS Address
,
109 OUT PAGE_ATTRIBUTE
*PageAttribute
123 BOOLEAN Enable5LevelPaging
;
125 GetPageTable (&PageTableBase
, &Enable5LevelPaging
);
127 Index5
= ((UINTN
)RShiftU64 (Address
, 48)) & PAGING_PAE_INDEX_MASK
;
128 Index4
= ((UINTN
)RShiftU64 (Address
, 39)) & PAGING_PAE_INDEX_MASK
;
129 Index3
= ((UINTN
)Address
>> 30) & PAGING_PAE_INDEX_MASK
;
130 Index2
= ((UINTN
)Address
>> 21) & PAGING_PAE_INDEX_MASK
;
131 Index1
= ((UINTN
)Address
>> 12) & PAGING_PAE_INDEX_MASK
;
133 if (sizeof (UINTN
) == sizeof (UINT64
)) {
134 if (Enable5LevelPaging
) {
135 L5PageTable
= (UINT64
*)PageTableBase
;
136 if (L5PageTable
[Index5
] == 0) {
137 *PageAttribute
= PageNone
;
141 L4PageTable
= (UINT64
*)(UINTN
)(L5PageTable
[Index5
] & ~mAddressEncMask
& PAGING_4K_ADDRESS_MASK_64
);
143 L4PageTable
= (UINT64
*)PageTableBase
;
146 if (L4PageTable
[Index4
] == 0) {
147 *PageAttribute
= PageNone
;
151 L3PageTable
= (UINT64
*)(UINTN
)(L4PageTable
[Index4
] & ~mAddressEncMask
& PAGING_4K_ADDRESS_MASK_64
);
153 L3PageTable
= (UINT64
*)PageTableBase
;
156 if (L3PageTable
[Index3
] == 0) {
157 *PageAttribute
= PageNone
;
161 if ((L3PageTable
[Index3
] & IA32_PG_PS
) != 0) {
163 *PageAttribute
= Page1G
;
164 return &L3PageTable
[Index3
];
167 L2PageTable
= (UINT64
*)(UINTN
)(L3PageTable
[Index3
] & ~mAddressEncMask
& PAGING_4K_ADDRESS_MASK_64
);
168 if (L2PageTable
[Index2
] == 0) {
169 *PageAttribute
= PageNone
;
173 if ((L2PageTable
[Index2
] & IA32_PG_PS
) != 0) {
175 *PageAttribute
= Page2M
;
176 return &L2PageTable
[Index2
];
180 L1PageTable
= (UINT64
*)(UINTN
)(L2PageTable
[Index2
] & ~mAddressEncMask
& PAGING_4K_ADDRESS_MASK_64
);
181 if ((L1PageTable
[Index1
] == 0) && (Address
!= 0)) {
182 *PageAttribute
= PageNone
;
186 *PageAttribute
= Page4K
;
187 return &L1PageTable
[Index1
];
191 Return memory attributes of page entry.
193 @param[in] PageEntry The page entry.
195 @return Memory attributes of page entry.
198 GetAttributesFromPageEntry (
205 if ((*PageEntry
& IA32_PG_P
) == 0) {
206 Attributes
|= EFI_MEMORY_RP
;
209 if ((*PageEntry
& IA32_PG_RW
) == 0) {
210 Attributes
|= EFI_MEMORY_RO
;
213 if ((*PageEntry
& IA32_PG_NX
) != 0) {
214 Attributes
|= EFI_MEMORY_XP
;
221 Modify memory attributes of page entry.
223 @param[in] PageEntry The page entry.
224 @param[in] Attributes The bit mask of attributes to modify for the memory region.
225 @param[in] IsSet TRUE means to set attributes. FALSE means to clear attributes.
226 @param[out] IsModified TRUE means page table modified. FALSE means page table not modified.
229 ConvertPageEntryAttribute (
230 IN UINT64
*PageEntry
,
231 IN UINT64 Attributes
,
233 OUT BOOLEAN
*IsModified
236 UINT64 CurrentPageEntry
;
239 CurrentPageEntry
= *PageEntry
;
240 NewPageEntry
= CurrentPageEntry
;
241 if ((Attributes
& EFI_MEMORY_RP
) != 0) {
243 NewPageEntry
&= ~(UINT64
)IA32_PG_P
;
245 NewPageEntry
|= IA32_PG_P
;
249 if ((Attributes
& EFI_MEMORY_RO
) != 0) {
251 NewPageEntry
&= ~(UINT64
)IA32_PG_RW
;
252 if (mInternalCr3
!= 0) {
254 // ReadOnly page need set Dirty bit for shadow stack
255 NewPageEntry
|= IA32_PG_D
;
256 // Clear user bit for supervisor shadow stack
257 NewPageEntry
&= ~(UINT64
)IA32_PG_U
;
260 // Clear dirty bit for non shadow stack, to protect RO page.
261 NewPageEntry
&= ~(UINT64
)IA32_PG_D
;
264 NewPageEntry
|= IA32_PG_RW
;
268 if ((Attributes
& EFI_MEMORY_XP
) != 0) {
271 NewPageEntry
|= IA32_PG_NX
;
273 NewPageEntry
&= ~IA32_PG_NX
;
278 *PageEntry
= NewPageEntry
;
279 if (CurrentPageEntry
!= NewPageEntry
) {
281 DEBUG ((DEBUG_VERBOSE
, "ConvertPageEntryAttribute 0x%lx", CurrentPageEntry
));
282 DEBUG ((DEBUG_VERBOSE
, "->0x%lx\n", NewPageEntry
));
289 This function returns if there is need to split page entry.
291 @param[in] BaseAddress The base address to be checked.
292 @param[in] Length The length to be checked.
293 @param[in] PageEntry The page entry to be checked.
294 @param[in] PageAttribute The page attribute of the page entry.
296 @retval SplitAttributes on if there is need to split page entry.
300 IN PHYSICAL_ADDRESS BaseAddress
,
302 IN UINT64
*PageEntry
,
303 IN PAGE_ATTRIBUTE PageAttribute
306 UINT64 PageEntryLength
;
308 PageEntryLength
= PageAttributeToLength (PageAttribute
);
310 if (((BaseAddress
& (PageEntryLength
- 1)) == 0) && (Length
>= PageEntryLength
)) {
314 if (((BaseAddress
& PAGING_2M_MASK
) != 0) || (Length
< SIZE_2MB
)) {
322 This function splits one page entry to small page entries.
324 @param[in] PageEntry The page entry to be splitted.
325 @param[in] PageAttribute The page attribute of the page entry.
326 @param[in] SplitAttribute How to split the page entry.
328 @retval RETURN_SUCCESS The page entry is splitted.
329 @retval RETURN_UNSUPPORTED The page entry does not support to be splitted.
330 @retval RETURN_OUT_OF_RESOURCES No resource to split page entry.
334 IN UINT64
*PageEntry
,
335 IN PAGE_ATTRIBUTE PageAttribute
,
336 IN PAGE_ATTRIBUTE SplitAttribute
340 UINT64
*NewPageEntry
;
343 ASSERT (PageAttribute
== Page2M
|| PageAttribute
== Page1G
);
345 if (PageAttribute
== Page2M
) {
349 ASSERT (SplitAttribute
== Page4K
);
350 if (SplitAttribute
== Page4K
) {
351 NewPageEntry
= AllocatePageTableMemory (1);
352 DEBUG ((DEBUG_VERBOSE
, "Split - 0x%x\n", NewPageEntry
));
353 if (NewPageEntry
== NULL
) {
354 return RETURN_OUT_OF_RESOURCES
;
357 BaseAddress
= *PageEntry
& PAGING_2M_ADDRESS_MASK_64
;
358 for (Index
= 0; Index
< SIZE_4KB
/ sizeof (UINT64
); Index
++) {
359 NewPageEntry
[Index
] = (BaseAddress
+ SIZE_4KB
* Index
) | mAddressEncMask
| ((*PageEntry
) & PAGE_PROGATE_BITS
);
362 (*PageEntry
) = (UINT64
)(UINTN
)NewPageEntry
| mAddressEncMask
| PAGE_ATTRIBUTE_BITS
;
363 return RETURN_SUCCESS
;
365 return RETURN_UNSUPPORTED
;
367 } else if (PageAttribute
== Page1G
) {
370 // No need support 1G->4K directly, we should use 1G->2M, then 2M->4K to get more compact page table.
372 ASSERT (SplitAttribute
== Page2M
|| SplitAttribute
== Page4K
);
373 if (((SplitAttribute
== Page2M
) || (SplitAttribute
== Page4K
))) {
374 NewPageEntry
= AllocatePageTableMemory (1);
375 DEBUG ((DEBUG_VERBOSE
, "Split - 0x%x\n", NewPageEntry
));
376 if (NewPageEntry
== NULL
) {
377 return RETURN_OUT_OF_RESOURCES
;
380 BaseAddress
= *PageEntry
& PAGING_1G_ADDRESS_MASK_64
;
381 for (Index
= 0; Index
< SIZE_4KB
/ sizeof (UINT64
); Index
++) {
382 NewPageEntry
[Index
] = (BaseAddress
+ SIZE_2MB
* Index
) | mAddressEncMask
| IA32_PG_PS
| ((*PageEntry
) & PAGE_PROGATE_BITS
);
385 (*PageEntry
) = (UINT64
)(UINTN
)NewPageEntry
| mAddressEncMask
| PAGE_ATTRIBUTE_BITS
;
386 return RETURN_SUCCESS
;
388 return RETURN_UNSUPPORTED
;
391 return RETURN_UNSUPPORTED
;
396 This function modifies the page attributes for the memory region specified by BaseAddress and
397 Length from their current attributes to the attributes specified by Attributes.
399 Caller should make sure BaseAddress and Length is at page boundary.
401 @param[in] BaseAddress The physical address that is the start address of a memory region.
402 @param[in] Length The size in bytes of the memory region.
403 @param[in] Attributes The bit mask of attributes to modify for the memory region.
404 @param[in] IsSet TRUE means to set attributes. FALSE means to clear attributes.
405 @param[out] IsSplitted TRUE means page table splitted. FALSE means page table not splitted.
406 @param[out] IsModified TRUE means page table modified. FALSE means page table not modified.
408 @retval RETURN_SUCCESS The attributes were modified for the memory region.
409 @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by
410 BaseAddress and Length cannot be modified.
411 @retval RETURN_INVALID_PARAMETER Length is zero.
412 Attributes specified an illegal combination of attributes that
413 cannot be set together.
414 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
415 the memory resource range.
416 @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the memory
417 resource range specified by BaseAddress and Length.
418 The bit mask of attributes is not support for the memory resource
419 range specified by BaseAddress and Length.
423 ConvertMemoryPageAttributes (
424 IN PHYSICAL_ADDRESS BaseAddress
,
426 IN UINT64 Attributes
,
428 OUT BOOLEAN
*IsSplitted OPTIONAL
,
429 OUT BOOLEAN
*IsModified OPTIONAL
433 PAGE_ATTRIBUTE PageAttribute
;
434 UINTN PageEntryLength
;
435 PAGE_ATTRIBUTE SplitAttribute
;
436 RETURN_STATUS Status
;
437 BOOLEAN IsEntryModified
;
438 EFI_PHYSICAL_ADDRESS MaximumSupportMemAddress
;
440 ASSERT (Attributes
!= 0);
441 ASSERT ((Attributes
& ~EFI_MEMORY_ATTRIBUTE_MASK
) == 0);
443 ASSERT ((BaseAddress
& (SIZE_4KB
- 1)) == 0);
444 ASSERT ((Length
& (SIZE_4KB
- 1)) == 0);
447 return RETURN_INVALID_PARAMETER
;
450 MaximumSupportMemAddress
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)(LShiftU64 (1, mPhysicalAddressBits
) - 1);
451 if (BaseAddress
> MaximumSupportMemAddress
) {
452 return RETURN_UNSUPPORTED
;
455 if (Length
> MaximumSupportMemAddress
) {
456 return RETURN_UNSUPPORTED
;
459 if ((Length
!= 0) && (BaseAddress
> MaximumSupportMemAddress
- (Length
- 1))) {
460 return RETURN_UNSUPPORTED
;
463 // DEBUG ((DEBUG_ERROR, "ConvertMemoryPageAttributes(%x) - %016lx, %016lx, %02lx\n", IsSet, BaseAddress, Length, Attributes));
465 if (IsSplitted
!= NULL
) {
469 if (IsModified
!= NULL
) {
474 // Below logic is to check 2M/4K page to make sure we do not waste memory.
476 while (Length
!= 0) {
477 PageEntry
= GetPageTableEntry (BaseAddress
, &PageAttribute
);
478 if (PageEntry
== NULL
) {
479 return RETURN_UNSUPPORTED
;
482 PageEntryLength
= PageAttributeToLength (PageAttribute
);
483 SplitAttribute
= NeedSplitPage (BaseAddress
, Length
, PageEntry
, PageAttribute
);
484 if (SplitAttribute
== PageNone
) {
485 ConvertPageEntryAttribute (PageEntry
, Attributes
, IsSet
, &IsEntryModified
);
486 if (IsEntryModified
) {
487 if (IsModified
!= NULL
) {
493 // Convert success, move to next
495 BaseAddress
+= PageEntryLength
;
496 Length
-= PageEntryLength
;
498 Status
= SplitPage (PageEntry
, PageAttribute
, SplitAttribute
);
499 if (RETURN_ERROR (Status
)) {
500 return RETURN_UNSUPPORTED
;
503 if (IsSplitted
!= NULL
) {
507 if (IsModified
!= NULL
) {
512 // Just split current page
513 // Convert success in next around
518 return RETURN_SUCCESS
;
522 FlushTlb on current processor.
524 @param[in,out] Buffer Pointer to private data buffer.
528 FlushTlbOnCurrentProcessor (
536 FlushTlb for all processors.
545 FlushTlbOnCurrentProcessor (NULL
);
547 for (Index
= 0; Index
< gSmst
->NumberOfCpus
; Index
++) {
548 if (Index
!= gSmst
->CurrentlyExecutingCpu
) {
549 // Force to start up AP in blocking mode,
550 SmmBlockingStartupThisAp (FlushTlbOnCurrentProcessor
, Index
, NULL
);
551 // Do not check return status, because AP might not be present in some corner cases.
557 This function sets the attributes for the memory region specified by BaseAddress and
558 Length from their current attributes to the attributes specified by Attributes.
560 @param[in] BaseAddress The physical address that is the start address of a memory region.
561 @param[in] Length The size in bytes of the memory region.
562 @param[in] Attributes The bit mask of attributes to set for the memory region.
563 @param[out] IsSplitted TRUE means page table splitted. FALSE means page table not splitted.
565 @retval EFI_SUCCESS The attributes were set for the memory region.
566 @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
567 BaseAddress and Length cannot be modified.
568 @retval EFI_INVALID_PARAMETER Length is zero.
569 Attributes specified an illegal combination of attributes that
570 cannot be set together.
571 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
572 the memory resource range.
573 @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
574 resource range specified by BaseAddress and Length.
575 The bit mask of attributes is not support for the memory resource
576 range specified by BaseAddress and Length.
581 SmmSetMemoryAttributesEx (
582 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
584 IN UINT64 Attributes
,
585 OUT BOOLEAN
*IsSplitted OPTIONAL
591 Status
= ConvertMemoryPageAttributes (BaseAddress
, Length
, Attributes
, TRUE
, IsSplitted
, &IsModified
);
592 if (!EFI_ERROR (Status
)) {
595 // Flush TLB as last step
605 This function clears the attributes for the memory region specified by BaseAddress and
606 Length from their current attributes to the attributes specified by Attributes.
608 @param[in] BaseAddress The physical address that is the start address of a memory region.
609 @param[in] Length The size in bytes of the memory region.
610 @param[in] Attributes The bit mask of attributes to clear for the memory region.
611 @param[out] IsSplitted TRUE means page table splitted. FALSE means page table not splitted.
613 @retval EFI_SUCCESS The attributes were cleared for the memory region.
614 @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
615 BaseAddress and Length cannot be modified.
616 @retval EFI_INVALID_PARAMETER Length is zero.
617 Attributes specified an illegal combination of attributes that
618 cannot be cleared together.
619 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
620 the memory resource range.
621 @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
622 resource range specified by BaseAddress and Length.
623 The bit mask of attributes is not supported for the memory resource
624 range specified by BaseAddress and Length.
629 SmmClearMemoryAttributesEx (
630 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
632 IN UINT64 Attributes
,
633 OUT BOOLEAN
*IsSplitted OPTIONAL
639 Status
= ConvertMemoryPageAttributes (BaseAddress
, Length
, Attributes
, FALSE
, IsSplitted
, &IsModified
);
640 if (!EFI_ERROR (Status
)) {
643 // Flush TLB as last step
653 This function sets the attributes for the memory region specified by BaseAddress and
654 Length from their current attributes to the attributes specified by Attributes.
656 @param[in] BaseAddress The physical address that is the start address of a memory region.
657 @param[in] Length The size in bytes of the memory region.
658 @param[in] Attributes The bit mask of attributes to set for the memory region.
660 @retval EFI_SUCCESS The attributes were set for the memory region.
661 @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
662 BaseAddress and Length cannot be modified.
663 @retval EFI_INVALID_PARAMETER Length is zero.
664 Attributes specified an illegal combination of attributes that
665 cannot be set together.
666 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
667 the memory resource range.
668 @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
669 resource range specified by BaseAddress and Length.
670 The bit mask of attributes is not supported for the memory resource
671 range specified by BaseAddress and Length.
676 SmmSetMemoryAttributes (
677 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
682 return SmmSetMemoryAttributesEx (BaseAddress
, Length
, Attributes
, NULL
);
686 This function clears the attributes for the memory region specified by BaseAddress and
687 Length from their current attributes to the attributes specified by Attributes.
689 @param[in] BaseAddress The physical address that is the start address of a memory region.
690 @param[in] Length The size in bytes of the memory region.
691 @param[in] Attributes The bit mask of attributes to clear for the memory region.
693 @retval EFI_SUCCESS The attributes were cleared for the memory region.
694 @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
695 BaseAddress and Length cannot be modified.
696 @retval EFI_INVALID_PARAMETER Length is zero.
697 Attributes specified an illegal combination of attributes that
698 cannot be cleared together.
699 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
700 the memory resource range.
701 @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
702 resource range specified by BaseAddress and Length.
703 The bit mask of attributes is not supported for the memory resource
704 range specified by BaseAddress and Length.
709 SmmClearMemoryAttributes (
710 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
715 return SmmClearMemoryAttributesEx (BaseAddress
, Length
, Attributes
, NULL
);
719 Set ShadowStack memory.
721 @param[in] Cr3 The page table base address.
722 @param[in] BaseAddress The physical address that is the start address of a memory region.
723 @param[in] Length The size in bytes of the memory region.
725 @retval EFI_SUCCESS The shadow stack memory is set.
730 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
736 SetPageTableBase (Cr3
);
738 Status
= SmmSetMemoryAttributes (BaseAddress
, Length
, EFI_MEMORY_RO
);
740 SetPageTableBase (0);
746 Set not present memory.
748 @param[in] Cr3 The page table base address.
749 @param[in] BaseAddress The physical address that is the start address of a memory region.
750 @param[in] Length The size in bytes of the memory region.
752 @retval EFI_SUCCESS The not present memory is set.
757 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
763 SetPageTableBase (Cr3
);
765 Status
= SmmSetMemoryAttributes (BaseAddress
, Length
, EFI_MEMORY_RP
);
767 SetPageTableBase (0);
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
;
1562 if ((Length
< SIZE_4KB
) || (Attributes
== NULL
)) {
1563 return EFI_INVALID_PARAMETER
;
1566 Size
= (INT64
)Length
;
1567 MemAttr
= (UINT64
)-1;
1570 PageEntry
= GetPageTableEntry (BaseAddress
, &PageAttr
);
1571 if ((PageEntry
== NULL
) || (PageAttr
== PageNone
)) {
1572 return EFI_UNSUPPORTED
;
1576 // If the memory range is cross page table boundary, make sure they
1577 // share the same attribute. Return EFI_NO_MAPPING if not.
1579 *Attributes
= GetAttributesFromPageEntry (PageEntry
);
1580 if ((MemAttr
!= (UINT64
)-1) && (*Attributes
!= MemAttr
)) {
1581 return EFI_NO_MAPPING
;
1586 Address
= *PageEntry
& ~mAddressEncMask
& PAGING_4K_ADDRESS_MASK_64
;
1587 Size
-= (SIZE_4KB
- (BaseAddress
- Address
));
1588 BaseAddress
+= (SIZE_4KB
- (BaseAddress
- Address
));
1592 Address
= *PageEntry
& ~mAddressEncMask
& PAGING_2M_ADDRESS_MASK_64
;
1593 Size
-= SIZE_2MB
- (BaseAddress
- Address
);
1594 BaseAddress
+= SIZE_2MB
- (BaseAddress
- Address
);
1598 Address
= *PageEntry
& ~mAddressEncMask
& PAGING_1G_ADDRESS_MASK_64
;
1599 Size
-= SIZE_1GB
- (BaseAddress
- Address
);
1600 BaseAddress
+= SIZE_1GB
- (BaseAddress
- Address
);
1604 return EFI_UNSUPPORTED
;
1607 MemAttr
= *Attributes
;