3 Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>
4 This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14 #include "PiSmmCpuDxeSmm.h"
17 // attributes for reserved memory before it is promoted to system memory
19 #define EFI_MEMORY_PRESENT 0x0100000000000000ULL
20 #define EFI_MEMORY_INITIALIZED 0x0200000000000000ULL
21 #define EFI_MEMORY_TESTED 0x0400000000000000ULL
23 #define PREVIOUS_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \
24 ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) - (Size)))
26 EFI_MEMORY_DESCRIPTOR
*mUefiMemoryMap
;
27 UINTN mUefiMemoryMapSize
;
28 UINTN mUefiDescriptorSize
;
30 EFI_GCD_MEMORY_SPACE_DESCRIPTOR
*mGcdMemSpace
= NULL
;
31 UINTN mGcdMemNumberOfDesc
= 0;
33 EFI_MEMORY_ATTRIBUTES_TABLE
*mUefiMemoryAttributesTable
= NULL
;
35 PAGE_ATTRIBUTE_TABLE mPageAttributeTable
[] = {
36 {Page4K
, SIZE_4KB
, PAGING_4K_ADDRESS_MASK_64
},
37 {Page2M
, SIZE_2MB
, PAGING_2M_ADDRESS_MASK_64
},
38 {Page1G
, SIZE_1GB
, PAGING_1G_ADDRESS_MASK_64
},
44 Set the internal page table base address.
45 If it is non zero, further MemoryAttribute modification will be on this page table.
46 If it is zero, further MemoryAttribute modification will be on real page table.
48 @param Cr3 page table base.
59 Return page table base.
61 @return page table base.
68 if (mInternalGr3
!= 0) {
71 return (AsmReadCr3 () & PAGING_4K_ADDRESS_MASK_64
);
75 Return length according to page attributes.
77 @param[in] PageAttributes The page attribute of the page entry.
79 @return The length of page entry.
82 PageAttributeToLength (
83 IN PAGE_ATTRIBUTE PageAttribute
87 for (Index
= 0; Index
< sizeof(mPageAttributeTable
)/sizeof(mPageAttributeTable
[0]); Index
++) {
88 if (PageAttribute
== mPageAttributeTable
[Index
].Attribute
) {
89 return (UINTN
)mPageAttributeTable
[Index
].Length
;
96 Return address mask according to page attributes.
98 @param[in] PageAttributes The page attribute of the page entry.
100 @return The address mask of page entry.
103 PageAttributeToMask (
104 IN PAGE_ATTRIBUTE PageAttribute
108 for (Index
= 0; Index
< sizeof(mPageAttributeTable
)/sizeof(mPageAttributeTable
[0]); Index
++) {
109 if (PageAttribute
== mPageAttributeTable
[Index
].Attribute
) {
110 return (UINTN
)mPageAttributeTable
[Index
].AddressMask
;
117 Return page table entry to match the address.
119 @param[in] Address The address to be checked.
120 @param[out] PageAttributes The page attribute of the page entry.
122 @return The page entry.
126 IN PHYSICAL_ADDRESS Address
,
127 OUT PAGE_ATTRIBUTE
*PageAttribute
139 Index4
= ((UINTN
)RShiftU64 (Address
, 39)) & PAGING_PAE_INDEX_MASK
;
140 Index3
= ((UINTN
)Address
>> 30) & PAGING_PAE_INDEX_MASK
;
141 Index2
= ((UINTN
)Address
>> 21) & PAGING_PAE_INDEX_MASK
;
142 Index1
= ((UINTN
)Address
>> 12) & PAGING_PAE_INDEX_MASK
;
144 if (sizeof(UINTN
) == sizeof(UINT64
)) {
145 L4PageTable
= (UINT64
*)GetPageTableBase ();
146 if (L4PageTable
[Index4
] == 0) {
147 *PageAttribute
= PageNone
;
151 L3PageTable
= (UINT64
*)(UINTN
)(L4PageTable
[Index4
] & ~mAddressEncMask
& PAGING_4K_ADDRESS_MASK_64
);
153 L3PageTable
= (UINT64
*)GetPageTableBase ();
155 if (L3PageTable
[Index3
] == 0) {
156 *PageAttribute
= PageNone
;
159 if ((L3PageTable
[Index3
] & IA32_PG_PS
) != 0) {
161 *PageAttribute
= Page1G
;
162 return &L3PageTable
[Index3
];
165 L2PageTable
= (UINT64
*)(UINTN
)(L3PageTable
[Index3
] & ~mAddressEncMask
& PAGING_4K_ADDRESS_MASK_64
);
166 if (L2PageTable
[Index2
] == 0) {
167 *PageAttribute
= PageNone
;
170 if ((L2PageTable
[Index2
] & IA32_PG_PS
) != 0) {
172 *PageAttribute
= Page2M
;
173 return &L2PageTable
[Index2
];
177 L1PageTable
= (UINT64
*)(UINTN
)(L2PageTable
[Index2
] & ~mAddressEncMask
& PAGING_4K_ADDRESS_MASK_64
);
178 if ((L1PageTable
[Index1
] == 0) && (Address
!= 0)) {
179 *PageAttribute
= PageNone
;
182 *PageAttribute
= Page4K
;
183 return &L1PageTable
[Index1
];
187 Return memory attributes of page entry.
189 @param[in] PageEntry The page entry.
191 @return Memory attributes of page entry.
194 GetAttributesFromPageEntry (
200 if ((*PageEntry
& IA32_PG_P
) == 0) {
201 Attributes
|= EFI_MEMORY_RP
;
203 if ((*PageEntry
& IA32_PG_RW
) == 0) {
204 Attributes
|= EFI_MEMORY_RO
;
206 if ((*PageEntry
& IA32_PG_NX
) != 0) {
207 Attributes
|= EFI_MEMORY_XP
;
213 Modify memory attributes of page entry.
215 @param[in] PageEntry The page entry.
216 @param[in] Attributes The bit mask of attributes to modify for the memory region.
217 @param[in] IsSet TRUE means to set attributes. FALSE means to clear attributes.
218 @param[out] IsModified TRUE means page table modified. FALSE means page table not modified.
221 ConvertPageEntryAttribute (
222 IN UINT64
*PageEntry
,
223 IN UINT64 Attributes
,
225 OUT BOOLEAN
*IsModified
228 UINT64 CurrentPageEntry
;
231 CurrentPageEntry
= *PageEntry
;
232 NewPageEntry
= CurrentPageEntry
;
233 if ((Attributes
& EFI_MEMORY_RP
) != 0) {
235 NewPageEntry
&= ~(UINT64
)IA32_PG_P
;
237 NewPageEntry
|= IA32_PG_P
;
240 if ((Attributes
& EFI_MEMORY_RO
) != 0) {
242 NewPageEntry
&= ~(UINT64
)IA32_PG_RW
;
243 if (mInternalGr3
!= 0) {
245 // ReadOnly page need set Dirty bit for shadow stack
246 NewPageEntry
|= IA32_PG_D
;
247 // Clear user bit for supervisor shadow stack
248 NewPageEntry
&= ~(UINT64
)IA32_PG_U
;
251 // Clear dirty bit for non shadow stack, to protect RO page.
252 NewPageEntry
&= ~(UINT64
)IA32_PG_D
;
255 NewPageEntry
|= IA32_PG_RW
;
258 if ((Attributes
& EFI_MEMORY_XP
) != 0) {
261 NewPageEntry
|= IA32_PG_NX
;
263 NewPageEntry
&= ~IA32_PG_NX
;
267 *PageEntry
= NewPageEntry
;
268 if (CurrentPageEntry
!= NewPageEntry
) {
270 DEBUG ((DEBUG_VERBOSE
, "ConvertPageEntryAttribute 0x%lx", CurrentPageEntry
));
271 DEBUG ((DEBUG_VERBOSE
, "->0x%lx\n", NewPageEntry
));
278 This function returns if there is need to split page entry.
280 @param[in] BaseAddress The base address to be checked.
281 @param[in] Length The length to be checked.
282 @param[in] PageEntry The page entry to be checked.
283 @param[in] PageAttribute The page attribute of the page entry.
285 @retval SplitAttributes on if there is need to split page entry.
289 IN PHYSICAL_ADDRESS BaseAddress
,
291 IN UINT64
*PageEntry
,
292 IN PAGE_ATTRIBUTE PageAttribute
295 UINT64 PageEntryLength
;
297 PageEntryLength
= PageAttributeToLength (PageAttribute
);
299 if (((BaseAddress
& (PageEntryLength
- 1)) == 0) && (Length
>= PageEntryLength
)) {
303 if (((BaseAddress
& PAGING_2M_MASK
) != 0) || (Length
< SIZE_2MB
)) {
311 This function splits one page entry to small page entries.
313 @param[in] PageEntry The page entry to be splitted.
314 @param[in] PageAttribute The page attribute of the page entry.
315 @param[in] SplitAttribute How to split the page entry.
317 @retval RETURN_SUCCESS The page entry is splitted.
318 @retval RETURN_UNSUPPORTED The page entry does not support to be splitted.
319 @retval RETURN_OUT_OF_RESOURCES No resource to split page entry.
323 IN UINT64
*PageEntry
,
324 IN PAGE_ATTRIBUTE PageAttribute
,
325 IN PAGE_ATTRIBUTE SplitAttribute
329 UINT64
*NewPageEntry
;
332 ASSERT (PageAttribute
== Page2M
|| PageAttribute
== Page1G
);
334 if (PageAttribute
== Page2M
) {
338 ASSERT (SplitAttribute
== Page4K
);
339 if (SplitAttribute
== Page4K
) {
340 NewPageEntry
= AllocatePageTableMemory (1);
341 DEBUG ((DEBUG_VERBOSE
, "Split - 0x%x\n", NewPageEntry
));
342 if (NewPageEntry
== NULL
) {
343 return RETURN_OUT_OF_RESOURCES
;
345 BaseAddress
= *PageEntry
& PAGING_2M_ADDRESS_MASK_64
;
346 for (Index
= 0; Index
< SIZE_4KB
/ sizeof(UINT64
); Index
++) {
347 NewPageEntry
[Index
] = (BaseAddress
+ SIZE_4KB
* Index
) | mAddressEncMask
| ((*PageEntry
) & PAGE_PROGATE_BITS
);
349 (*PageEntry
) = (UINT64
)(UINTN
)NewPageEntry
| mAddressEncMask
| PAGE_ATTRIBUTE_BITS
;
350 return RETURN_SUCCESS
;
352 return RETURN_UNSUPPORTED
;
354 } else if (PageAttribute
== Page1G
) {
357 // No need support 1G->4K directly, we should use 1G->2M, then 2M->4K to get more compact page table.
359 ASSERT (SplitAttribute
== Page2M
|| SplitAttribute
== Page4K
);
360 if ((SplitAttribute
== Page2M
|| SplitAttribute
== Page4K
)) {
361 NewPageEntry
= AllocatePageTableMemory (1);
362 DEBUG ((DEBUG_VERBOSE
, "Split - 0x%x\n", NewPageEntry
));
363 if (NewPageEntry
== NULL
) {
364 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
);
370 (*PageEntry
) = (UINT64
)(UINTN
)NewPageEntry
| mAddressEncMask
| PAGE_ATTRIBUTE_BITS
;
371 return RETURN_SUCCESS
;
373 return RETURN_UNSUPPORTED
;
376 return RETURN_UNSUPPORTED
;
381 This function modifies the page attributes for the memory region specified by BaseAddress and
382 Length from their current attributes to the attributes specified by Attributes.
384 Caller should make sure BaseAddress and Length is at page boundary.
386 @param[in] BaseAddress The physical address that is the start address of a memory region.
387 @param[in] Length The size in bytes of the memory region.
388 @param[in] Attributes The bit mask of attributes to modify for the memory region.
389 @param[in] IsSet TRUE means to set attributes. FALSE means to clear attributes.
390 @param[out] IsSplitted TRUE means page table splitted. FALSE means page table not splitted.
391 @param[out] IsModified TRUE means page table modified. FALSE means page table not modified.
393 @retval RETURN_SUCCESS The attributes were modified for the memory region.
394 @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by
395 BaseAddress and Length cannot be modified.
396 @retval RETURN_INVALID_PARAMETER Length is zero.
397 Attributes specified an illegal combination of attributes that
398 cannot be set together.
399 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
400 the memory resource range.
401 @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the memory
402 resource range specified by BaseAddress and Length.
403 The bit mask of attributes is not support for the memory resource
404 range specified by BaseAddress and Length.
408 ConvertMemoryPageAttributes (
409 IN PHYSICAL_ADDRESS BaseAddress
,
411 IN UINT64 Attributes
,
413 OUT BOOLEAN
*IsSplitted
, OPTIONAL
414 OUT BOOLEAN
*IsModified OPTIONAL
418 PAGE_ATTRIBUTE PageAttribute
;
419 UINTN PageEntryLength
;
420 PAGE_ATTRIBUTE SplitAttribute
;
421 RETURN_STATUS Status
;
422 BOOLEAN IsEntryModified
;
423 EFI_PHYSICAL_ADDRESS MaximumSupportMemAddress
;
425 ASSERT (Attributes
!= 0);
426 ASSERT ((Attributes
& ~(EFI_MEMORY_RP
| EFI_MEMORY_RO
| EFI_MEMORY_XP
)) == 0);
428 ASSERT ((BaseAddress
& (SIZE_4KB
- 1)) == 0);
429 ASSERT ((Length
& (SIZE_4KB
- 1)) == 0);
432 return RETURN_INVALID_PARAMETER
;
435 MaximumSupportMemAddress
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)(LShiftU64 (1, mPhysicalAddressBits
) - 1);
436 if (BaseAddress
> MaximumSupportMemAddress
) {
437 return RETURN_UNSUPPORTED
;
439 if (Length
> MaximumSupportMemAddress
) {
440 return RETURN_UNSUPPORTED
;
442 if ((Length
!= 0) && (BaseAddress
> MaximumSupportMemAddress
- (Length
- 1))) {
443 return RETURN_UNSUPPORTED
;
446 // DEBUG ((DEBUG_ERROR, "ConvertMemoryPageAttributes(%x) - %016lx, %016lx, %02lx\n", IsSet, BaseAddress, Length, Attributes));
448 if (IsSplitted
!= NULL
) {
451 if (IsModified
!= NULL
) {
456 // Below logic is to check 2M/4K page to make sure we donot waist memory.
458 while (Length
!= 0) {
459 PageEntry
= GetPageTableEntry (BaseAddress
, &PageAttribute
);
460 if (PageEntry
== NULL
) {
461 return RETURN_UNSUPPORTED
;
463 PageEntryLength
= PageAttributeToLength (PageAttribute
);
464 SplitAttribute
= NeedSplitPage (BaseAddress
, Length
, PageEntry
, PageAttribute
);
465 if (SplitAttribute
== PageNone
) {
466 ConvertPageEntryAttribute (PageEntry
, Attributes
, IsSet
, &IsEntryModified
);
467 if (IsEntryModified
) {
468 if (IsModified
!= NULL
) {
473 // Convert success, move to next
475 BaseAddress
+= PageEntryLength
;
476 Length
-= PageEntryLength
;
478 Status
= SplitPage (PageEntry
, PageAttribute
, SplitAttribute
);
479 if (RETURN_ERROR (Status
)) {
480 return RETURN_UNSUPPORTED
;
482 if (IsSplitted
!= NULL
) {
485 if (IsModified
!= NULL
) {
489 // Just split current page
490 // Convert success in next around
495 return RETURN_SUCCESS
;
499 FlushTlb on current processor.
501 @param[in,out] Buffer Pointer to private data buffer.
505 FlushTlbOnCurrentProcessor (
513 FlushTlb for all processors.
522 FlushTlbOnCurrentProcessor (NULL
);
524 for (Index
= 0; Index
< gSmst
->NumberOfCpus
; Index
++) {
525 if (Index
!= gSmst
->CurrentlyExecutingCpu
) {
526 // Force to start up AP in blocking mode,
527 SmmBlockingStartupThisAp (FlushTlbOnCurrentProcessor
, Index
, NULL
);
528 // Do not check return status, because AP might not be present in some corner cases.
534 This function sets the attributes for the memory region specified by BaseAddress and
535 Length from their current attributes to the attributes specified by Attributes.
537 @param[in] BaseAddress The physical address that is the start address of a memory region.
538 @param[in] Length The size in bytes of the memory region.
539 @param[in] Attributes The bit mask of attributes to set for the memory region.
540 @param[out] IsSplitted TRUE means page table splitted. FALSE means page table not splitted.
542 @retval EFI_SUCCESS The attributes were set for the memory region.
543 @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
544 BaseAddress and Length cannot be modified.
545 @retval EFI_INVALID_PARAMETER Length is zero.
546 Attributes specified an illegal combination of attributes that
547 cannot be set together.
548 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
549 the memory resource range.
550 @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
551 resource range specified by BaseAddress and Length.
552 The bit mask of attributes is not support for the memory resource
553 range specified by BaseAddress and Length.
558 SmmSetMemoryAttributesEx (
559 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
561 IN UINT64 Attributes
,
562 OUT BOOLEAN
*IsSplitted OPTIONAL
568 Status
= ConvertMemoryPageAttributes (BaseAddress
, Length
, Attributes
, TRUE
, IsSplitted
, &IsModified
);
569 if (!EFI_ERROR(Status
)) {
572 // Flush TLB as last step
582 This function clears the attributes for the memory region specified by BaseAddress and
583 Length from their current attributes to the attributes specified by Attributes.
585 @param[in] BaseAddress The physical address that is the start address of a memory region.
586 @param[in] Length The size in bytes of the memory region.
587 @param[in] Attributes The bit mask of attributes to clear for the memory region.
588 @param[out] IsSplitted TRUE means page table splitted. FALSE means page table not splitted.
590 @retval EFI_SUCCESS The attributes were cleared for the memory region.
591 @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
592 BaseAddress and Length cannot be modified.
593 @retval EFI_INVALID_PARAMETER Length is zero.
594 Attributes specified an illegal combination of attributes that
595 cannot be cleared together.
596 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
597 the memory resource range.
598 @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
599 resource range specified by BaseAddress and Length.
600 The bit mask of attributes is not supported for the memory resource
601 range specified by BaseAddress and Length.
606 SmmClearMemoryAttributesEx (
607 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
609 IN UINT64 Attributes
,
610 OUT BOOLEAN
*IsSplitted OPTIONAL
616 Status
= ConvertMemoryPageAttributes (BaseAddress
, Length
, Attributes
, FALSE
, IsSplitted
, &IsModified
);
617 if (!EFI_ERROR(Status
)) {
620 // Flush TLB as last step
630 This function sets the attributes for the memory region specified by BaseAddress and
631 Length from their current attributes to the attributes specified by Attributes.
633 @param[in] BaseAddress The physical address that is the start address of a memory region.
634 @param[in] Length The size in bytes of the memory region.
635 @param[in] Attributes The bit mask of attributes to set for the memory region.
637 @retval EFI_SUCCESS The attributes were set for the memory region.
638 @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
639 BaseAddress and Length cannot be modified.
640 @retval EFI_INVALID_PARAMETER Length is zero.
641 Attributes specified an illegal combination of attributes that
642 cannot be set together.
643 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
644 the memory resource range.
645 @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
646 resource range specified by BaseAddress and Length.
647 The bit mask of attributes is not supported for the memory resource
648 range specified by BaseAddress and Length.
653 SmmSetMemoryAttributes (
654 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
659 return SmmSetMemoryAttributesEx (BaseAddress
, Length
, Attributes
, NULL
);
663 This function clears the attributes for the memory region specified by BaseAddress and
664 Length from their current attributes to the attributes specified by Attributes.
666 @param[in] BaseAddress The physical address that is the start address of a memory region.
667 @param[in] Length The size in bytes of the memory region.
668 @param[in] Attributes The bit mask of attributes to clear for the memory region.
670 @retval EFI_SUCCESS The attributes were cleared for the memory region.
671 @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
672 BaseAddress and Length cannot be modified.
673 @retval EFI_INVALID_PARAMETER Length is zero.
674 Attributes specified an illegal combination of attributes that
675 cannot be cleared together.
676 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
677 the memory resource range.
678 @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
679 resource range specified by BaseAddress and Length.
680 The bit mask of attributes is not supported for the memory resource
681 range specified by BaseAddress and Length.
686 SmmClearMemoryAttributes (
687 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
692 return SmmClearMemoryAttributesEx (BaseAddress
, Length
, Attributes
, NULL
);
696 Set ShadowStack memory.
698 @param[in] Cr3 The page table base address.
699 @param[in] BaseAddress The physical address that is the start address of a memory region.
700 @param[in] Length The size in bytes of the memory region.
702 @retval EFI_SUCCESS The shadow stack memory is set.
707 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
713 SetPageTableBase (Cr3
);
715 Status
= SmmSetMemoryAttributes (BaseAddress
, Length
, EFI_MEMORY_RO
);
717 SetPageTableBase (0);
723 Set not present memory.
725 @param[in] Cr3 The page table base address.
726 @param[in] BaseAddress The physical address that is the start address of a memory region.
727 @param[in] Length The size in bytes of the memory region.
729 @retval EFI_SUCCESS The not present memory is set.
734 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
740 SetPageTableBase (Cr3
);
742 Status
= SmmSetMemoryAttributes (BaseAddress
, Length
, EFI_MEMORY_RP
);
744 SetPageTableBase (0);
750 Retrieves a pointer to the system configuration table from the SMM System Table
751 based on a specified GUID.
753 @param[in] TableGuid The pointer to table's GUID type.
754 @param[out] Table The pointer to the table associated with TableGuid in the EFI System Table.
756 @retval EFI_SUCCESS A configuration table matching TableGuid was found.
757 @retval EFI_NOT_FOUND A configuration table matching TableGuid could not be found.
762 SmmGetSystemConfigurationTable (
763 IN EFI_GUID
*TableGuid
,
769 ASSERT (TableGuid
!= NULL
);
770 ASSERT (Table
!= NULL
);
773 for (Index
= 0; Index
< gSmst
->NumberOfTableEntries
; Index
++) {
774 if (CompareGuid (TableGuid
, &(gSmst
->SmmConfigurationTable
[Index
].VendorGuid
))) {
775 *Table
= gSmst
->SmmConfigurationTable
[Index
].VendorTable
;
780 return EFI_NOT_FOUND
;
784 This function sets SMM save state buffer to be RW and XP.
787 PatchSmmSaveStateMap (
796 TileCodeSize
= GetSmiHandlerSize ();
797 TileCodeSize
= ALIGN_VALUE(TileCodeSize
, SIZE_4KB
);
798 TileDataSize
= (SMRAM_SAVE_STATE_MAP_OFFSET
- SMM_PSD_OFFSET
) + sizeof (SMRAM_SAVE_STATE_MAP
);
799 TileDataSize
= ALIGN_VALUE(TileDataSize
, SIZE_4KB
);
800 TileSize
= TileDataSize
+ TileCodeSize
- 1;
801 TileSize
= 2 * GetPowerOfTwo32 ((UINT32
)TileSize
);
803 DEBUG ((DEBUG_INFO
, "PatchSmmSaveStateMap:\n"));
804 for (Index
= 0; Index
< mMaxNumberOfCpus
- 1; Index
++) {
808 SmmSetMemoryAttributes (
809 mCpuHotPlugData
.SmBase
[Index
] + SMM_HANDLER_OFFSET
,
813 SmmClearMemoryAttributes (
814 mCpuHotPlugData
.SmBase
[Index
] + SMM_HANDLER_OFFSET
,
822 SmmClearMemoryAttributes (
823 mCpuHotPlugData
.SmBase
[Index
] + SMM_HANDLER_OFFSET
+ TileCodeSize
,
824 TileSize
- TileCodeSize
,
827 SmmSetMemoryAttributes (
828 mCpuHotPlugData
.SmBase
[Index
] + SMM_HANDLER_OFFSET
+ TileCodeSize
,
829 TileSize
- TileCodeSize
,
837 SmmSetMemoryAttributes (
838 mCpuHotPlugData
.SmBase
[mMaxNumberOfCpus
- 1] + SMM_HANDLER_OFFSET
,
842 SmmClearMemoryAttributes (
843 mCpuHotPlugData
.SmBase
[mMaxNumberOfCpus
- 1] + SMM_HANDLER_OFFSET
,
851 SmmClearMemoryAttributes (
852 mCpuHotPlugData
.SmBase
[mMaxNumberOfCpus
- 1] + SMM_HANDLER_OFFSET
+ TileCodeSize
,
853 SIZE_32KB
- TileCodeSize
,
856 SmmSetMemoryAttributes (
857 mCpuHotPlugData
.SmBase
[mMaxNumberOfCpus
- 1] + SMM_HANDLER_OFFSET
+ TileCodeSize
,
858 SIZE_32KB
- TileCodeSize
,
864 This function sets GDT/IDT buffer to be RO and XP.
871 EFI_PHYSICAL_ADDRESS BaseAddress
;
877 DEBUG ((DEBUG_INFO
, "PatchGdtIdtMap - GDT:\n"));
879 BaseAddress
= mGdtBuffer
;
880 Size
= ALIGN_VALUE(mGdtBufferSize
, SIZE_4KB
);
882 // The range should have been set to RO
883 // if it is allocated with EfiRuntimeServicesCode.
885 SmmSetMemoryAttributes (
894 DEBUG ((DEBUG_INFO
, "PatchGdtIdtMap - IDT:\n"));
896 BaseAddress
= gcSmiIdtr
.Base
;
897 Size
= ALIGN_VALUE(gcSmiIdtr
.Limit
+ 1, SIZE_4KB
);
899 // The range should have been set to RO
900 // if it is allocated with EfiRuntimeServicesCode.
902 SmmSetMemoryAttributes (
910 This function sets memory attribute according to MemoryAttributesTable.
913 SetMemMapAttributes (
917 EFI_MEMORY_DESCRIPTOR
*MemoryMap
;
918 EFI_MEMORY_DESCRIPTOR
*MemoryMapStart
;
919 UINTN MemoryMapEntryCount
;
920 UINTN DescriptorSize
;
922 EDKII_PI_SMM_MEMORY_ATTRIBUTES_TABLE
*MemoryAttributesTable
;
924 SmmGetSystemConfigurationTable (&gEdkiiPiSmmMemoryAttributesTableGuid
, (VOID
**)&MemoryAttributesTable
);
925 if (MemoryAttributesTable
== NULL
) {
926 DEBUG ((DEBUG_INFO
, "MemoryAttributesTable - NULL\n"));
930 DEBUG ((DEBUG_INFO
, "MemoryAttributesTable:\n"));
931 DEBUG ((DEBUG_INFO
, " Version - 0x%08x\n", MemoryAttributesTable
->Version
));
932 DEBUG ((DEBUG_INFO
, " NumberOfEntries - 0x%08x\n", MemoryAttributesTable
->NumberOfEntries
));
933 DEBUG ((DEBUG_INFO
, " DescriptorSize - 0x%08x\n", MemoryAttributesTable
->DescriptorSize
));
935 MemoryMapEntryCount
= MemoryAttributesTable
->NumberOfEntries
;
936 DescriptorSize
= MemoryAttributesTable
->DescriptorSize
;
937 MemoryMapStart
= (EFI_MEMORY_DESCRIPTOR
*)(MemoryAttributesTable
+ 1);
938 MemoryMap
= MemoryMapStart
;
939 for (Index
= 0; Index
< MemoryMapEntryCount
; Index
++) {
940 DEBUG ((DEBUG_INFO
, "Entry (0x%x)\n", MemoryMap
));
941 DEBUG ((DEBUG_INFO
, " Type - 0x%x\n", MemoryMap
->Type
));
942 DEBUG ((DEBUG_INFO
, " PhysicalStart - 0x%016lx\n", MemoryMap
->PhysicalStart
));
943 DEBUG ((DEBUG_INFO
, " VirtualStart - 0x%016lx\n", MemoryMap
->VirtualStart
));
944 DEBUG ((DEBUG_INFO
, " NumberOfPages - 0x%016lx\n", MemoryMap
->NumberOfPages
));
945 DEBUG ((DEBUG_INFO
, " Attribute - 0x%016lx\n", MemoryMap
->Attribute
));
946 MemoryMap
= NEXT_MEMORY_DESCRIPTOR(MemoryMap
, DescriptorSize
);
949 MemoryMap
= MemoryMapStart
;
950 for (Index
= 0; Index
< MemoryMapEntryCount
; Index
++) {
951 DEBUG ((DEBUG_VERBOSE
, "SetAttribute: Memory Entry - 0x%lx, 0x%x\n", MemoryMap
->PhysicalStart
, MemoryMap
->NumberOfPages
));
952 switch (MemoryMap
->Type
) {
953 case EfiRuntimeServicesCode
:
954 SmmSetMemoryAttributes (
955 MemoryMap
->PhysicalStart
,
956 EFI_PAGES_TO_SIZE((UINTN
)MemoryMap
->NumberOfPages
),
960 case EfiRuntimeServicesData
:
961 SmmSetMemoryAttributes (
962 MemoryMap
->PhysicalStart
,
963 EFI_PAGES_TO_SIZE((UINTN
)MemoryMap
->NumberOfPages
),
968 SmmSetMemoryAttributes (
969 MemoryMap
->PhysicalStart
,
970 EFI_PAGES_TO_SIZE((UINTN
)MemoryMap
->NumberOfPages
),
975 MemoryMap
= NEXT_MEMORY_DESCRIPTOR(MemoryMap
, DescriptorSize
);
978 PatchSmmSaveStateMap ();
985 Sort memory map entries based upon PhysicalStart, from low to high.
987 @param MemoryMap A pointer to the buffer in which firmware places
988 the current memory map.
989 @param MemoryMapSize Size, in bytes, of the MemoryMap buffer.
990 @param DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
995 IN OUT EFI_MEMORY_DESCRIPTOR
*MemoryMap
,
996 IN UINTN MemoryMapSize
,
997 IN UINTN DescriptorSize
1000 EFI_MEMORY_DESCRIPTOR
*MemoryMapEntry
;
1001 EFI_MEMORY_DESCRIPTOR
*NextMemoryMapEntry
;
1002 EFI_MEMORY_DESCRIPTOR
*MemoryMapEnd
;
1003 EFI_MEMORY_DESCRIPTOR TempMemoryMap
;
1005 MemoryMapEntry
= MemoryMap
;
1006 NextMemoryMapEntry
= NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry
, DescriptorSize
);
1007 MemoryMapEnd
= (EFI_MEMORY_DESCRIPTOR
*) ((UINT8
*) MemoryMap
+ MemoryMapSize
);
1008 while (MemoryMapEntry
< MemoryMapEnd
) {
1009 while (NextMemoryMapEntry
< MemoryMapEnd
) {
1010 if (MemoryMapEntry
->PhysicalStart
> NextMemoryMapEntry
->PhysicalStart
) {
1011 CopyMem (&TempMemoryMap
, MemoryMapEntry
, sizeof(EFI_MEMORY_DESCRIPTOR
));
1012 CopyMem (MemoryMapEntry
, NextMemoryMapEntry
, sizeof(EFI_MEMORY_DESCRIPTOR
));
1013 CopyMem (NextMemoryMapEntry
, &TempMemoryMap
, sizeof(EFI_MEMORY_DESCRIPTOR
));
1016 NextMemoryMapEntry
= NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry
, DescriptorSize
);
1019 MemoryMapEntry
= NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry
, DescriptorSize
);
1020 NextMemoryMapEntry
= NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry
, DescriptorSize
);
1025 Return if a UEFI memory page should be marked as not present in SMM page table.
1026 If the memory map entries type is
1027 EfiLoaderCode/Data, EfiBootServicesCode/Data, EfiConventionalMemory,
1028 EfiUnusableMemory, EfiACPIReclaimMemory, return TRUE.
1031 @param[in] MemoryMap A pointer to the memory descriptor.
1033 @return TRUE The memory described will be marked as not present in SMM page table.
1034 @return FALSE The memory described will not be marked as not present in SMM page table.
1037 IsUefiPageNotPresent (
1038 IN EFI_MEMORY_DESCRIPTOR
*MemoryMap
1041 switch (MemoryMap
->Type
) {
1044 case EfiBootServicesCode
:
1045 case EfiBootServicesData
:
1046 case EfiConventionalMemory
:
1047 case EfiUnusableMemory
:
1048 case EfiACPIReclaimMemory
:
1056 Merge continous memory map entries whose type is
1057 EfiLoaderCode/Data, EfiBootServicesCode/Data, EfiConventionalMemory,
1058 EfiUnusableMemory, EfiACPIReclaimMemory, because the memory described by
1059 these entries will be set as NOT present in SMM page table.
1061 @param[in, out] MemoryMap A pointer to the buffer in which firmware places
1062 the current memory map.
1063 @param[in, out] MemoryMapSize A pointer to the size, in bytes, of the
1064 MemoryMap buffer. On input, this is the size of
1065 the current memory map. On output,
1066 it is the size of new memory map after merge.
1067 @param[in] DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
1071 MergeMemoryMapForNotPresentEntry (
1072 IN OUT EFI_MEMORY_DESCRIPTOR
*MemoryMap
,
1073 IN OUT UINTN
*MemoryMapSize
,
1074 IN UINTN DescriptorSize
1077 EFI_MEMORY_DESCRIPTOR
*MemoryMapEntry
;
1078 EFI_MEMORY_DESCRIPTOR
*MemoryMapEnd
;
1079 UINT64 MemoryBlockLength
;
1080 EFI_MEMORY_DESCRIPTOR
*NewMemoryMapEntry
;
1081 EFI_MEMORY_DESCRIPTOR
*NextMemoryMapEntry
;
1083 MemoryMapEntry
= MemoryMap
;
1084 NewMemoryMapEntry
= MemoryMap
;
1085 MemoryMapEnd
= (EFI_MEMORY_DESCRIPTOR
*) ((UINT8
*) MemoryMap
+ *MemoryMapSize
);
1086 while ((UINTN
)MemoryMapEntry
< (UINTN
)MemoryMapEnd
) {
1087 CopyMem (NewMemoryMapEntry
, MemoryMapEntry
, sizeof(EFI_MEMORY_DESCRIPTOR
));
1088 NextMemoryMapEntry
= NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry
, DescriptorSize
);
1091 MemoryBlockLength
= (UINT64
) (EFI_PAGES_TO_SIZE((UINTN
)MemoryMapEntry
->NumberOfPages
));
1092 if (((UINTN
)NextMemoryMapEntry
< (UINTN
)MemoryMapEnd
) &&
1093 IsUefiPageNotPresent(MemoryMapEntry
) && IsUefiPageNotPresent(NextMemoryMapEntry
) &&
1094 ((MemoryMapEntry
->PhysicalStart
+ MemoryBlockLength
) == NextMemoryMapEntry
->PhysicalStart
)) {
1095 MemoryMapEntry
->NumberOfPages
+= NextMemoryMapEntry
->NumberOfPages
;
1096 if (NewMemoryMapEntry
!= MemoryMapEntry
) {
1097 NewMemoryMapEntry
->NumberOfPages
+= NextMemoryMapEntry
->NumberOfPages
;
1100 NextMemoryMapEntry
= NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry
, DescriptorSize
);
1103 MemoryMapEntry
= PREVIOUS_MEMORY_DESCRIPTOR (NextMemoryMapEntry
, DescriptorSize
);
1108 MemoryMapEntry
= NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry
, DescriptorSize
);
1109 NewMemoryMapEntry
= NEXT_MEMORY_DESCRIPTOR (NewMemoryMapEntry
, DescriptorSize
);
1112 *MemoryMapSize
= (UINTN
)NewMemoryMapEntry
- (UINTN
)MemoryMap
;
1118 This function caches the GCD memory map information.
1125 UINTN NumberOfDescriptors
;
1126 EFI_GCD_MEMORY_SPACE_DESCRIPTOR
*MemSpaceMap
;
1130 Status
= gDS
->GetMemorySpaceMap (&NumberOfDescriptors
, &MemSpaceMap
);
1131 if (EFI_ERROR (Status
)) {
1135 mGcdMemNumberOfDesc
= 0;
1136 for (Index
= 0; Index
< NumberOfDescriptors
; Index
++) {
1137 if (MemSpaceMap
[Index
].GcdMemoryType
== EfiGcdMemoryTypeReserved
&&
1138 (MemSpaceMap
[Index
].Capabilities
& (EFI_MEMORY_PRESENT
| EFI_MEMORY_INITIALIZED
| EFI_MEMORY_TESTED
)) ==
1139 (EFI_MEMORY_PRESENT
| EFI_MEMORY_INITIALIZED
)
1141 mGcdMemNumberOfDesc
++;
1145 mGcdMemSpace
= AllocateZeroPool (mGcdMemNumberOfDesc
* sizeof (EFI_GCD_MEMORY_SPACE_DESCRIPTOR
));
1146 ASSERT (mGcdMemSpace
!= NULL
);
1147 if (mGcdMemSpace
== NULL
) {
1148 mGcdMemNumberOfDesc
= 0;
1149 gBS
->FreePool (MemSpaceMap
);
1153 mGcdMemNumberOfDesc
= 0;
1154 for (Index
= 0; Index
< NumberOfDescriptors
; Index
++) {
1155 if (MemSpaceMap
[Index
].GcdMemoryType
== EfiGcdMemoryTypeReserved
&&
1156 (MemSpaceMap
[Index
].Capabilities
& (EFI_MEMORY_PRESENT
| EFI_MEMORY_INITIALIZED
| EFI_MEMORY_TESTED
)) ==
1157 (EFI_MEMORY_PRESENT
| EFI_MEMORY_INITIALIZED
)
1160 &mGcdMemSpace
[mGcdMemNumberOfDesc
],
1161 &MemSpaceMap
[Index
],
1162 sizeof(EFI_GCD_MEMORY_SPACE_DESCRIPTOR
)
1164 mGcdMemNumberOfDesc
++;
1168 gBS
->FreePool (MemSpaceMap
);
1172 Get UEFI MemoryAttributesTable.
1175 GetUefiMemoryAttributesTable (
1180 EFI_MEMORY_ATTRIBUTES_TABLE
*MemoryAttributesTable
;
1181 UINTN MemoryAttributesTableSize
;
1183 Status
= EfiGetSystemConfigurationTable (&gEfiMemoryAttributesTableGuid
, (VOID
**)&MemoryAttributesTable
);
1184 if (!EFI_ERROR (Status
) && (MemoryAttributesTable
!= NULL
)) {
1185 MemoryAttributesTableSize
= sizeof(EFI_MEMORY_ATTRIBUTES_TABLE
) + MemoryAttributesTable
->DescriptorSize
* MemoryAttributesTable
->NumberOfEntries
;
1186 mUefiMemoryAttributesTable
= AllocateCopyPool (MemoryAttributesTableSize
, MemoryAttributesTable
);
1187 ASSERT (mUefiMemoryAttributesTable
!= NULL
);
1192 This function caches the UEFI memory map information.
1201 UINT32 DescriptorVersion
;
1202 EFI_MEMORY_DESCRIPTOR
*MemoryMap
;
1203 UINTN UefiMemoryMapSize
;
1205 DEBUG ((DEBUG_INFO
, "GetUefiMemoryMap\n"));
1207 UefiMemoryMapSize
= 0;
1209 Status
= gBS
->GetMemoryMap (
1213 &mUefiDescriptorSize
,
1216 ASSERT (Status
== EFI_BUFFER_TOO_SMALL
);
1219 Status
= gBS
->AllocatePool (EfiBootServicesData
, UefiMemoryMapSize
, (VOID
**)&MemoryMap
);
1220 ASSERT (MemoryMap
!= NULL
);
1221 if (MemoryMap
== NULL
) {
1225 Status
= gBS
->GetMemoryMap (
1229 &mUefiDescriptorSize
,
1232 if (EFI_ERROR (Status
)) {
1233 gBS
->FreePool (MemoryMap
);
1236 } while (Status
== EFI_BUFFER_TOO_SMALL
);
1238 if (MemoryMap
== NULL
) {
1242 SortMemoryMap (MemoryMap
, UefiMemoryMapSize
, mUefiDescriptorSize
);
1243 MergeMemoryMapForNotPresentEntry (MemoryMap
, &UefiMemoryMapSize
, mUefiDescriptorSize
);
1245 mUefiMemoryMapSize
= UefiMemoryMapSize
;
1246 mUefiMemoryMap
= AllocateCopyPool (UefiMemoryMapSize
, MemoryMap
);
1247 ASSERT (mUefiMemoryMap
!= NULL
);
1249 gBS
->FreePool (MemoryMap
);
1252 // Get additional information from GCD memory map.
1257 // Get UEFI memory attributes table.
1259 GetUefiMemoryAttributesTable ();
1263 This function sets UEFI memory attribute according to UEFI memory map.
1265 The normal memory region is marked as not present, such as
1266 EfiLoaderCode/Data, EfiBootServicesCode/Data, EfiConventionalMemory,
1267 EfiUnusableMemory, EfiACPIReclaimMemory.
1270 SetUefiMemMapAttributes (
1275 EFI_MEMORY_DESCRIPTOR
*MemoryMap
;
1276 UINTN MemoryMapEntryCount
;
1278 EFI_MEMORY_DESCRIPTOR
*Entry
;
1280 DEBUG ((DEBUG_INFO
, "SetUefiMemMapAttributes\n"));
1282 if (mUefiMemoryMap
!= NULL
) {
1283 MemoryMapEntryCount
= mUefiMemoryMapSize
/mUefiDescriptorSize
;
1284 MemoryMap
= mUefiMemoryMap
;
1285 for (Index
= 0; Index
< MemoryMapEntryCount
; Index
++) {
1286 if (IsUefiPageNotPresent(MemoryMap
)) {
1287 Status
= SmmSetMemoryAttributes (
1288 MemoryMap
->PhysicalStart
,
1289 EFI_PAGES_TO_SIZE((UINTN
)MemoryMap
->NumberOfPages
),
1294 "UefiMemory protection: 0x%lx - 0x%lx %r\n",
1295 MemoryMap
->PhysicalStart
,
1296 MemoryMap
->PhysicalStart
+ (UINT64
)EFI_PAGES_TO_SIZE((UINTN
)MemoryMap
->NumberOfPages
),
1300 MemoryMap
= NEXT_MEMORY_DESCRIPTOR(MemoryMap
, mUefiDescriptorSize
);
1304 // Do not free mUefiMemoryMap, it will be checked in IsSmmCommBufferForbiddenAddress().
1308 // Set untested memory as not present.
1310 if (mGcdMemSpace
!= NULL
) {
1311 for (Index
= 0; Index
< mGcdMemNumberOfDesc
; Index
++) {
1312 Status
= SmmSetMemoryAttributes (
1313 mGcdMemSpace
[Index
].BaseAddress
,
1314 mGcdMemSpace
[Index
].Length
,
1319 "GcdMemory protection: 0x%lx - 0x%lx %r\n",
1320 mGcdMemSpace
[Index
].BaseAddress
,
1321 mGcdMemSpace
[Index
].BaseAddress
+ mGcdMemSpace
[Index
].Length
,
1327 // Do not free mGcdMemSpace, it will be checked in IsSmmCommBufferForbiddenAddress().
1331 // Set UEFI runtime memory with EFI_MEMORY_RO as not present.
1333 if (mUefiMemoryAttributesTable
!= NULL
) {
1334 Entry
= (EFI_MEMORY_DESCRIPTOR
*)(mUefiMemoryAttributesTable
+ 1);
1335 for (Index
= 0; Index
< mUefiMemoryAttributesTable
->NumberOfEntries
; Index
++) {
1336 if (Entry
->Type
== EfiRuntimeServicesCode
|| Entry
->Type
== EfiRuntimeServicesData
) {
1337 if ((Entry
->Attribute
& EFI_MEMORY_RO
) != 0) {
1338 Status
= SmmSetMemoryAttributes (
1339 Entry
->PhysicalStart
,
1340 EFI_PAGES_TO_SIZE((UINTN
)Entry
->NumberOfPages
),
1345 "UefiMemoryAttribute protection: 0x%lx - 0x%lx %r\n",
1346 Entry
->PhysicalStart
,
1347 Entry
->PhysicalStart
+ (UINT64
)EFI_PAGES_TO_SIZE((UINTN
)Entry
->NumberOfPages
),
1352 Entry
= NEXT_MEMORY_DESCRIPTOR (Entry
, mUefiMemoryAttributesTable
->DescriptorSize
);
1356 // Do not free mUefiMemoryAttributesTable, it will be checked in IsSmmCommBufferForbiddenAddress().
1361 Return if the Address is forbidden as SMM communication buffer.
1363 @param[in] Address the address to be checked
1365 @return TRUE The address is forbidden as SMM communication buffer.
1366 @return FALSE The address is allowed as SMM communication buffer.
1369 IsSmmCommBufferForbiddenAddress (
1373 EFI_MEMORY_DESCRIPTOR
*MemoryMap
;
1374 UINTN MemoryMapEntryCount
;
1376 EFI_MEMORY_DESCRIPTOR
*Entry
;
1378 if (mUefiMemoryMap
!= NULL
) {
1379 MemoryMap
= mUefiMemoryMap
;
1380 MemoryMapEntryCount
= mUefiMemoryMapSize
/mUefiDescriptorSize
;
1381 for (Index
= 0; Index
< MemoryMapEntryCount
; Index
++) {
1382 if (IsUefiPageNotPresent (MemoryMap
)) {
1383 if ((Address
>= MemoryMap
->PhysicalStart
) &&
1384 (Address
< MemoryMap
->PhysicalStart
+ EFI_PAGES_TO_SIZE((UINTN
)MemoryMap
->NumberOfPages
)) ) {
1388 MemoryMap
= NEXT_MEMORY_DESCRIPTOR(MemoryMap
, mUefiDescriptorSize
);
1392 if (mGcdMemSpace
!= NULL
) {
1393 for (Index
= 0; Index
< mGcdMemNumberOfDesc
; Index
++) {
1394 if ((Address
>= mGcdMemSpace
[Index
].BaseAddress
) &&
1395 (Address
< mGcdMemSpace
[Index
].BaseAddress
+ mGcdMemSpace
[Index
].Length
) ) {
1401 if (mUefiMemoryAttributesTable
!= NULL
) {
1402 Entry
= (EFI_MEMORY_DESCRIPTOR
*)(mUefiMemoryAttributesTable
+ 1);
1403 for (Index
= 0; Index
< mUefiMemoryAttributesTable
->NumberOfEntries
; Index
++) {
1404 if (Entry
->Type
== EfiRuntimeServicesCode
|| Entry
->Type
== EfiRuntimeServicesData
) {
1405 if ((Entry
->Attribute
& EFI_MEMORY_RO
) != 0) {
1406 if ((Address
>= Entry
->PhysicalStart
) &&
1407 (Address
< Entry
->PhysicalStart
+ LShiftU64 (Entry
->NumberOfPages
, EFI_PAGE_SHIFT
))) {
1410 Entry
= NEXT_MEMORY_DESCRIPTOR (Entry
, mUefiMemoryAttributesTable
->DescriptorSize
);
1419 This function set given attributes of the memory region specified by
1420 BaseAddress and Length.
1422 @param This The EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL instance.
1423 @param BaseAddress The physical address that is the start address of
1425 @param Length The size in bytes of the memory region.
1426 @param Attributes The bit mask of attributes to set for the memory
1429 @retval EFI_SUCCESS The attributes were set for the memory region.
1430 @retval EFI_INVALID_PARAMETER Length is zero.
1431 Attributes specified an illegal combination of
1432 attributes that cannot be set together.
1433 @retval EFI_UNSUPPORTED The processor does not support one or more
1434 bytes of the memory resource range specified
1435 by BaseAddress and Length.
1436 The bit mask of attributes is not supported for
1437 the memory resource range specified by
1438 BaseAddress and Length.
1443 EdkiiSmmSetMemoryAttributes (
1444 IN EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL
*This
,
1445 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
1447 IN UINT64 Attributes
1450 return SmmSetMemoryAttributes (BaseAddress
, Length
, Attributes
);
1454 This function clears given attributes of the memory region specified by
1455 BaseAddress and Length.
1457 @param This The EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL instance.
1458 @param BaseAddress The physical address that is the start address of
1460 @param Length The size in bytes of the memory region.
1461 @param Attributes The bit mask of attributes to clear for the memory
1464 @retval EFI_SUCCESS The attributes were cleared for the memory region.
1465 @retval EFI_INVALID_PARAMETER Length is zero.
1466 Attributes specified an illegal combination of
1467 attributes that cannot be cleared together.
1468 @retval EFI_UNSUPPORTED The processor does not support one or more
1469 bytes of the memory resource range specified
1470 by BaseAddress and Length.
1471 The bit mask of attributes is not supported for
1472 the memory resource range specified by
1473 BaseAddress and Length.
1478 EdkiiSmmClearMemoryAttributes (
1479 IN EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL
*This
,
1480 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
1482 IN UINT64 Attributes
1485 return SmmClearMemoryAttributes (BaseAddress
, Length
, Attributes
);
1489 This function retrieves the attributes of the memory region specified by
1490 BaseAddress and Length. If different attributes are got from different part
1491 of the memory region, EFI_NO_MAPPING will be returned.
1493 @param This The EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL instance.
1494 @param BaseAddress The physical address that is the start address of
1496 @param Length The size in bytes of the memory region.
1497 @param Attributes Pointer to attributes returned.
1499 @retval EFI_SUCCESS The attributes got for the memory region.
1500 @retval EFI_INVALID_PARAMETER Length is zero.
1502 @retval EFI_NO_MAPPING Attributes are not consistent cross the memory
1504 @retval EFI_UNSUPPORTED The processor does not support one or more
1505 bytes of the memory resource range specified
1506 by BaseAddress and Length.
1511 EdkiiSmmGetMemoryAttributes (
1512 IN EDKII_SMM_MEMORY_ATTRIBUTE_PROTOCOL
*This
,
1513 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
1515 OUT UINT64
*Attributes
1518 EFI_PHYSICAL_ADDRESS Address
;
1521 PAGE_ATTRIBUTE PageAttr
;
1524 if (Length
< SIZE_4KB
|| Attributes
== NULL
) {
1525 return EFI_INVALID_PARAMETER
;
1528 Size
= (INT64
)Length
;
1529 MemAttr
= (UINT64
)-1;
1533 PageEntry
= GetPageTableEntry (BaseAddress
, &PageAttr
);
1534 if (PageEntry
== NULL
|| PageAttr
== PageNone
) {
1535 return EFI_UNSUPPORTED
;
1539 // If the memory range is cross page table boundary, make sure they
1540 // share the same attribute. Return EFI_NO_MAPPING if not.
1542 *Attributes
= GetAttributesFromPageEntry (PageEntry
);
1543 if (MemAttr
!= (UINT64
)-1 && *Attributes
!= MemAttr
) {
1544 return EFI_NO_MAPPING
;
1549 Address
= *PageEntry
& ~mAddressEncMask
& PAGING_4K_ADDRESS_MASK_64
;
1550 Size
-= (SIZE_4KB
- (BaseAddress
- Address
));
1551 BaseAddress
+= (SIZE_4KB
- (BaseAddress
- Address
));
1555 Address
= *PageEntry
& ~mAddressEncMask
& PAGING_2M_ADDRESS_MASK_64
;
1556 Size
-= SIZE_2MB
- (BaseAddress
- Address
);
1557 BaseAddress
+= SIZE_2MB
- (BaseAddress
- Address
);
1561 Address
= *PageEntry
& ~mAddressEncMask
& PAGING_1G_ADDRESS_MASK_64
;
1562 Size
-= SIZE_1GB
- (BaseAddress
- Address
);
1563 BaseAddress
+= SIZE_1GB
- (BaseAddress
- Address
);
1567 return EFI_UNSUPPORTED
;
1570 MemAttr
= *Attributes
;