3 Copyright (c) 2016 - 2017, 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"
16 #define NEXT_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \
17 ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) + (Size)))
19 #define PREVIOUS_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \
20 ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) - (Size)))
22 EFI_MEMORY_DESCRIPTOR
*mUefiMemoryMap
;
23 UINTN mUefiMemoryMapSize
;
24 UINTN mUefiDescriptorSize
;
26 PAGE_ATTRIBUTE_TABLE mPageAttributeTable
[] = {
27 {Page4K
, SIZE_4KB
, PAGING_4K_ADDRESS_MASK_64
},
28 {Page2M
, SIZE_2MB
, PAGING_2M_ADDRESS_MASK_64
},
29 {Page1G
, SIZE_1GB
, PAGING_1G_ADDRESS_MASK_64
},
33 Return page table base.
35 @return page table base.
42 return (AsmReadCr3 () & PAGING_4K_ADDRESS_MASK_64
);
46 Return length according to page attributes.
48 @param[in] PageAttributes The page attribute of the page entry.
50 @return The length of page entry.
53 PageAttributeToLength (
54 IN PAGE_ATTRIBUTE PageAttribute
58 for (Index
= 0; Index
< sizeof(mPageAttributeTable
)/sizeof(mPageAttributeTable
[0]); Index
++) {
59 if (PageAttribute
== mPageAttributeTable
[Index
].Attribute
) {
60 return (UINTN
)mPageAttributeTable
[Index
].Length
;
67 Return address mask according to page attributes.
69 @param[in] PageAttributes The page attribute of the page entry.
71 @return The address mask of page entry.
75 IN PAGE_ATTRIBUTE PageAttribute
79 for (Index
= 0; Index
< sizeof(mPageAttributeTable
)/sizeof(mPageAttributeTable
[0]); Index
++) {
80 if (PageAttribute
== mPageAttributeTable
[Index
].Attribute
) {
81 return (UINTN
)mPageAttributeTable
[Index
].AddressMask
;
88 Return page table entry to match the address.
90 @param[in] Address The address to be checked.
91 @param[out] PageAttributes The page attribute of the page entry.
93 @return The page entry.
97 IN PHYSICAL_ADDRESS Address
,
98 OUT PAGE_ATTRIBUTE
*PageAttribute
110 Index4
= ((UINTN
)RShiftU64 (Address
, 39)) & PAGING_PAE_INDEX_MASK
;
111 Index3
= ((UINTN
)Address
>> 30) & PAGING_PAE_INDEX_MASK
;
112 Index2
= ((UINTN
)Address
>> 21) & PAGING_PAE_INDEX_MASK
;
113 Index1
= ((UINTN
)Address
>> 12) & PAGING_PAE_INDEX_MASK
;
115 if (sizeof(UINTN
) == sizeof(UINT64
)) {
116 L4PageTable
= (UINT64
*)GetPageTableBase ();
117 if (L4PageTable
[Index4
] == 0) {
118 *PageAttribute
= PageNone
;
122 L3PageTable
= (UINT64
*)(UINTN
)(L4PageTable
[Index4
] & ~mAddressEncMask
& PAGING_4K_ADDRESS_MASK_64
);
124 L3PageTable
= (UINT64
*)GetPageTableBase ();
126 if (L3PageTable
[Index3
] == 0) {
127 *PageAttribute
= PageNone
;
130 if ((L3PageTable
[Index3
] & IA32_PG_PS
) != 0) {
132 *PageAttribute
= Page1G
;
133 return &L3PageTable
[Index3
];
136 L2PageTable
= (UINT64
*)(UINTN
)(L3PageTable
[Index3
] & ~mAddressEncMask
& PAGING_4K_ADDRESS_MASK_64
);
137 if (L2PageTable
[Index2
] == 0) {
138 *PageAttribute
= PageNone
;
141 if ((L2PageTable
[Index2
] & IA32_PG_PS
) != 0) {
143 *PageAttribute
= Page2M
;
144 return &L2PageTable
[Index2
];
148 L1PageTable
= (UINT64
*)(UINTN
)(L2PageTable
[Index2
] & ~mAddressEncMask
& PAGING_4K_ADDRESS_MASK_64
);
149 if ((L1PageTable
[Index1
] == 0) && (Address
!= 0)) {
150 *PageAttribute
= PageNone
;
153 *PageAttribute
= Page4K
;
154 return &L1PageTable
[Index1
];
158 Return memory attributes of page entry.
160 @param[in] PageEntry The page entry.
162 @return Memory attributes of page entry.
165 GetAttributesFromPageEntry (
171 if ((*PageEntry
& IA32_PG_P
) == 0) {
172 Attributes
|= EFI_MEMORY_RP
;
174 if ((*PageEntry
& IA32_PG_RW
) == 0) {
175 Attributes
|= EFI_MEMORY_RO
;
177 if ((*PageEntry
& IA32_PG_NX
) != 0) {
178 Attributes
|= EFI_MEMORY_XP
;
184 Modify memory attributes of page entry.
186 @param[in] PageEntry The page entry.
187 @param[in] Attributes The bit mask of attributes to modify for the memory region.
188 @param[in] IsSet TRUE means to set attributes. FALSE means to clear attributes.
189 @param[out] IsModified TRUE means page table modified. FALSE means page table not modified.
192 ConvertPageEntryAttribute (
193 IN UINT64
*PageEntry
,
194 IN UINT64 Attributes
,
196 OUT BOOLEAN
*IsModified
199 UINT64 CurrentPageEntry
;
202 CurrentPageEntry
= *PageEntry
;
203 NewPageEntry
= CurrentPageEntry
;
204 if ((Attributes
& EFI_MEMORY_RP
) != 0) {
206 NewPageEntry
&= ~(UINT64
)IA32_PG_P
;
208 NewPageEntry
|= IA32_PG_P
;
211 if ((Attributes
& EFI_MEMORY_RO
) != 0) {
213 NewPageEntry
&= ~(UINT64
)IA32_PG_RW
;
215 NewPageEntry
|= IA32_PG_RW
;
218 if ((Attributes
& EFI_MEMORY_XP
) != 0) {
221 NewPageEntry
|= IA32_PG_NX
;
223 NewPageEntry
&= ~IA32_PG_NX
;
227 *PageEntry
= NewPageEntry
;
228 if (CurrentPageEntry
!= NewPageEntry
) {
230 DEBUG ((DEBUG_VERBOSE
, "ConvertPageEntryAttribute 0x%lx", CurrentPageEntry
));
231 DEBUG ((DEBUG_VERBOSE
, "->0x%lx\n", NewPageEntry
));
238 This function returns if there is need to split page entry.
240 @param[in] BaseAddress The base address to be checked.
241 @param[in] Length The length to be checked.
242 @param[in] PageEntry The page entry to be checked.
243 @param[in] PageAttribute The page attribute of the page entry.
245 @retval SplitAttributes on if there is need to split page entry.
249 IN PHYSICAL_ADDRESS BaseAddress
,
251 IN UINT64
*PageEntry
,
252 IN PAGE_ATTRIBUTE PageAttribute
255 UINT64 PageEntryLength
;
257 PageEntryLength
= PageAttributeToLength (PageAttribute
);
259 if (((BaseAddress
& (PageEntryLength
- 1)) == 0) && (Length
>= PageEntryLength
)) {
263 if (((BaseAddress
& PAGING_2M_MASK
) != 0) || (Length
< SIZE_2MB
)) {
271 This function splits one page entry to small page entries.
273 @param[in] PageEntry The page entry to be splitted.
274 @param[in] PageAttribute The page attribute of the page entry.
275 @param[in] SplitAttribute How to split the page entry.
277 @retval RETURN_SUCCESS The page entry is splitted.
278 @retval RETURN_UNSUPPORTED The page entry does not support to be splitted.
279 @retval RETURN_OUT_OF_RESOURCES No resource to split page entry.
283 IN UINT64
*PageEntry
,
284 IN PAGE_ATTRIBUTE PageAttribute
,
285 IN PAGE_ATTRIBUTE SplitAttribute
289 UINT64
*NewPageEntry
;
292 ASSERT (PageAttribute
== Page2M
|| PageAttribute
== Page1G
);
294 if (PageAttribute
== Page2M
) {
298 ASSERT (SplitAttribute
== Page4K
);
299 if (SplitAttribute
== Page4K
) {
300 NewPageEntry
= AllocatePageTableMemory (1);
301 DEBUG ((DEBUG_VERBOSE
, "Split - 0x%x\n", NewPageEntry
));
302 if (NewPageEntry
== NULL
) {
303 return RETURN_OUT_OF_RESOURCES
;
305 BaseAddress
= *PageEntry
& PAGING_2M_ADDRESS_MASK_64
;
306 for (Index
= 0; Index
< SIZE_4KB
/ sizeof(UINT64
); Index
++) {
307 NewPageEntry
[Index
] = (BaseAddress
+ SIZE_4KB
* Index
) | mAddressEncMask
| ((*PageEntry
) & PAGE_PROGATE_BITS
);
309 (*PageEntry
) = (UINT64
)(UINTN
)NewPageEntry
| mAddressEncMask
| PAGE_ATTRIBUTE_BITS
;
310 return RETURN_SUCCESS
;
312 return RETURN_UNSUPPORTED
;
314 } else if (PageAttribute
== Page1G
) {
317 // No need support 1G->4K directly, we should use 1G->2M, then 2M->4K to get more compact page table.
319 ASSERT (SplitAttribute
== Page2M
|| SplitAttribute
== Page4K
);
320 if ((SplitAttribute
== Page2M
|| SplitAttribute
== Page4K
)) {
321 NewPageEntry
= AllocatePageTableMemory (1);
322 DEBUG ((DEBUG_VERBOSE
, "Split - 0x%x\n", NewPageEntry
));
323 if (NewPageEntry
== NULL
) {
324 return RETURN_OUT_OF_RESOURCES
;
326 BaseAddress
= *PageEntry
& PAGING_1G_ADDRESS_MASK_64
;
327 for (Index
= 0; Index
< SIZE_4KB
/ sizeof(UINT64
); Index
++) {
328 NewPageEntry
[Index
] = (BaseAddress
+ SIZE_2MB
* Index
) | mAddressEncMask
| IA32_PG_PS
| ((*PageEntry
) & PAGE_PROGATE_BITS
);
330 (*PageEntry
) = (UINT64
)(UINTN
)NewPageEntry
| mAddressEncMask
| PAGE_ATTRIBUTE_BITS
;
331 return RETURN_SUCCESS
;
333 return RETURN_UNSUPPORTED
;
336 return RETURN_UNSUPPORTED
;
341 This function modifies the page attributes for the memory region specified by BaseAddress and
342 Length from their current attributes to the attributes specified by Attributes.
344 Caller should make sure BaseAddress and Length is at page boundary.
346 @param[in] BaseAddress The physical address that is the start address of a memory region.
347 @param[in] Length The size in bytes of the memory region.
348 @param[in] Attributes The bit mask of attributes to modify for the memory region.
349 @param[in] IsSet TRUE means to set attributes. FALSE means to clear attributes.
350 @param[out] IsSplitted TRUE means page table splitted. FALSE means page table not splitted.
351 @param[out] IsModified TRUE means page table modified. FALSE means page table not modified.
353 @retval RETURN_SUCCESS The attributes were modified for the memory region.
354 @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by
355 BaseAddress and Length cannot be modified.
356 @retval RETURN_INVALID_PARAMETER Length is zero.
357 Attributes specified an illegal combination of attributes that
358 cannot be set together.
359 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
360 the memory resource range.
361 @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the memory
362 resource range specified by BaseAddress and Length.
363 The bit mask of attributes is not support for the memory resource
364 range specified by BaseAddress and Length.
368 ConvertMemoryPageAttributes (
369 IN PHYSICAL_ADDRESS BaseAddress
,
371 IN UINT64 Attributes
,
373 OUT BOOLEAN
*IsSplitted
, OPTIONAL
374 OUT BOOLEAN
*IsModified OPTIONAL
378 PAGE_ATTRIBUTE PageAttribute
;
379 UINTN PageEntryLength
;
380 PAGE_ATTRIBUTE SplitAttribute
;
381 RETURN_STATUS Status
;
382 BOOLEAN IsEntryModified
;
383 EFI_PHYSICAL_ADDRESS MaximumSupportMemAddress
;
385 ASSERT (Attributes
!= 0);
386 ASSERT ((Attributes
& ~(EFI_MEMORY_RP
| EFI_MEMORY_RO
| EFI_MEMORY_XP
)) == 0);
388 ASSERT ((BaseAddress
& (SIZE_4KB
- 1)) == 0);
389 ASSERT ((Length
& (SIZE_4KB
- 1)) == 0);
392 return RETURN_INVALID_PARAMETER
;
395 MaximumSupportMemAddress
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)(LShiftU64 (1, mPhysicalAddressBits
) - 1);
396 if (BaseAddress
> MaximumSupportMemAddress
) {
397 return RETURN_UNSUPPORTED
;
399 if (Length
> MaximumSupportMemAddress
) {
400 return RETURN_UNSUPPORTED
;
402 if ((Length
!= 0) && (BaseAddress
> MaximumSupportMemAddress
- (Length
- 1))) {
403 return RETURN_UNSUPPORTED
;
406 // DEBUG ((DEBUG_ERROR, "ConvertMemoryPageAttributes(%x) - %016lx, %016lx, %02lx\n", IsSet, BaseAddress, Length, Attributes));
408 if (IsSplitted
!= NULL
) {
411 if (IsModified
!= NULL
) {
416 // Below logic is to check 2M/4K page to make sure we donot waist memory.
418 while (Length
!= 0) {
419 PageEntry
= GetPageTableEntry (BaseAddress
, &PageAttribute
);
420 if (PageEntry
== NULL
) {
421 return RETURN_UNSUPPORTED
;
423 PageEntryLength
= PageAttributeToLength (PageAttribute
);
424 SplitAttribute
= NeedSplitPage (BaseAddress
, Length
, PageEntry
, PageAttribute
);
425 if (SplitAttribute
== PageNone
) {
426 ConvertPageEntryAttribute (PageEntry
, Attributes
, IsSet
, &IsEntryModified
);
427 if (IsEntryModified
) {
428 if (IsModified
!= NULL
) {
433 // Convert success, move to next
435 BaseAddress
+= PageEntryLength
;
436 Length
-= PageEntryLength
;
438 Status
= SplitPage (PageEntry
, PageAttribute
, SplitAttribute
);
439 if (RETURN_ERROR (Status
)) {
440 return RETURN_UNSUPPORTED
;
442 if (IsSplitted
!= NULL
) {
445 if (IsModified
!= NULL
) {
449 // Just split current page
450 // Convert success in next around
455 return RETURN_SUCCESS
;
459 FlushTlb on current processor.
461 @param[in,out] Buffer Pointer to private data buffer.
465 FlushTlbOnCurrentProcessor (
473 FlushTlb for all processors.
482 FlushTlbOnCurrentProcessor (NULL
);
484 for (Index
= 0; Index
< gSmst
->NumberOfCpus
; Index
++) {
485 if (Index
!= gSmst
->CurrentlyExecutingCpu
) {
486 // Force to start up AP in blocking mode,
487 SmmBlockingStartupThisAp (FlushTlbOnCurrentProcessor
, Index
, NULL
);
488 // Do not check return status, because AP might not be present in some corner cases.
494 This function sets the attributes for the memory region specified by BaseAddress and
495 Length from their current attributes to the attributes specified by Attributes.
497 @param[in] BaseAddress The physical address that is the start address of a memory region.
498 @param[in] Length The size in bytes of the memory region.
499 @param[in] Attributes The bit mask of attributes to set for the memory region.
500 @param[out] IsSplitted TRUE means page table splitted. FALSE means page table not splitted.
502 @retval EFI_SUCCESS The attributes were set for the memory region.
503 @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
504 BaseAddress and Length cannot be modified.
505 @retval EFI_INVALID_PARAMETER Length is zero.
506 Attributes specified an illegal combination of attributes that
507 cannot be set together.
508 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
509 the memory resource range.
510 @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
511 resource range specified by BaseAddress and Length.
512 The bit mask of attributes is not support for the memory resource
513 range specified by BaseAddress and Length.
518 SmmSetMemoryAttributesEx (
519 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
521 IN UINT64 Attributes
,
522 OUT BOOLEAN
*IsSplitted OPTIONAL
528 Status
= ConvertMemoryPageAttributes (BaseAddress
, Length
, Attributes
, TRUE
, IsSplitted
, &IsModified
);
529 if (!EFI_ERROR(Status
)) {
532 // Flush TLB as last step
542 This function clears the attributes for the memory region specified by BaseAddress and
543 Length from their current attributes to the attributes specified by Attributes.
545 @param[in] BaseAddress The physical address that is the start address of a memory region.
546 @param[in] Length The size in bytes of the memory region.
547 @param[in] Attributes The bit mask of attributes to clear for the memory region.
548 @param[out] IsSplitted TRUE means page table splitted. FALSE means page table not splitted.
550 @retval EFI_SUCCESS The attributes were cleared for the memory region.
551 @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
552 BaseAddress and Length cannot be modified.
553 @retval EFI_INVALID_PARAMETER Length is zero.
554 Attributes specified an illegal combination of attributes that
555 cannot be set together.
556 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
557 the memory resource range.
558 @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
559 resource range specified by BaseAddress and Length.
560 The bit mask of attributes is not support for the memory resource
561 range specified by BaseAddress and Length.
566 SmmClearMemoryAttributesEx (
567 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
569 IN UINT64 Attributes
,
570 OUT BOOLEAN
*IsSplitted OPTIONAL
576 Status
= ConvertMemoryPageAttributes (BaseAddress
, Length
, Attributes
, FALSE
, IsSplitted
, &IsModified
);
577 if (!EFI_ERROR(Status
)) {
580 // Flush TLB as last step
590 This function sets the attributes for the memory region specified by BaseAddress and
591 Length from their current attributes to the attributes specified by Attributes.
593 @param[in] BaseAddress The physical address that is the start address of a memory region.
594 @param[in] Length The size in bytes of the memory region.
595 @param[in] Attributes The bit mask of attributes to set for the memory region.
597 @retval EFI_SUCCESS The attributes were set for the memory region.
598 @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
599 BaseAddress and Length cannot be modified.
600 @retval EFI_INVALID_PARAMETER Length is zero.
601 Attributes specified an illegal combination of attributes that
602 cannot be set together.
603 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
604 the memory resource range.
605 @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
606 resource range specified by BaseAddress and Length.
607 The bit mask of attributes is not support for the memory resource
608 range specified by BaseAddress and Length.
613 SmmSetMemoryAttributes (
614 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
619 return SmmSetMemoryAttributesEx (BaseAddress
, Length
, Attributes
, NULL
);
623 This function clears the attributes for the memory region specified by BaseAddress and
624 Length from their current attributes to the attributes specified by Attributes.
626 @param[in] BaseAddress The physical address that is the start address of a memory region.
627 @param[in] Length The size in bytes of the memory region.
628 @param[in] Attributes The bit mask of attributes to clear for the memory region.
630 @retval EFI_SUCCESS The attributes were cleared for the memory region.
631 @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
632 BaseAddress and Length cannot be modified.
633 @retval EFI_INVALID_PARAMETER Length is zero.
634 Attributes specified an illegal combination of attributes that
635 cannot be set together.
636 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
637 the memory resource range.
638 @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
639 resource range specified by BaseAddress and Length.
640 The bit mask of attributes is not support for the memory resource
641 range specified by BaseAddress and Length.
646 SmmClearMemoryAttributes (
647 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
652 return SmmClearMemoryAttributesEx (BaseAddress
, Length
, Attributes
, NULL
);
658 Retrieves a pointer to the system configuration table from the SMM System Table
659 based on a specified GUID.
661 @param[in] TableGuid The pointer to table's GUID type.
662 @param[out] Table The pointer to the table associated with TableGuid in the EFI System Table.
664 @retval EFI_SUCCESS A configuration table matching TableGuid was found.
665 @retval EFI_NOT_FOUND A configuration table matching TableGuid could not be found.
670 SmmGetSystemConfigurationTable (
671 IN EFI_GUID
*TableGuid
,
677 ASSERT (TableGuid
!= NULL
);
678 ASSERT (Table
!= NULL
);
681 for (Index
= 0; Index
< gSmst
->NumberOfTableEntries
; Index
++) {
682 if (CompareGuid (TableGuid
, &(gSmst
->SmmConfigurationTable
[Index
].VendorGuid
))) {
683 *Table
= gSmst
->SmmConfigurationTable
[Index
].VendorTable
;
688 return EFI_NOT_FOUND
;
692 This function sets SMM save state buffer to be RW and XP.
695 PatchSmmSaveStateMap (
704 TileCodeSize
= GetSmiHandlerSize ();
705 TileCodeSize
= ALIGN_VALUE(TileCodeSize
, SIZE_4KB
);
706 TileDataSize
= (SMRAM_SAVE_STATE_MAP_OFFSET
- SMM_PSD_OFFSET
) + sizeof (SMRAM_SAVE_STATE_MAP
);
707 TileDataSize
= ALIGN_VALUE(TileDataSize
, SIZE_4KB
);
708 TileSize
= TileDataSize
+ TileCodeSize
- 1;
709 TileSize
= 2 * GetPowerOfTwo32 ((UINT32
)TileSize
);
711 DEBUG ((DEBUG_INFO
, "PatchSmmSaveStateMap:\n"));
712 for (Index
= 0; Index
< mMaxNumberOfCpus
- 1; Index
++) {
716 SmmSetMemoryAttributes (
717 mCpuHotPlugData
.SmBase
[Index
] + SMM_HANDLER_OFFSET
,
721 SmmClearMemoryAttributes (
722 mCpuHotPlugData
.SmBase
[Index
] + SMM_HANDLER_OFFSET
,
730 SmmClearMemoryAttributes (
731 mCpuHotPlugData
.SmBase
[Index
] + SMM_HANDLER_OFFSET
+ TileCodeSize
,
732 TileSize
- TileCodeSize
,
735 SmmSetMemoryAttributes (
736 mCpuHotPlugData
.SmBase
[Index
] + SMM_HANDLER_OFFSET
+ TileCodeSize
,
737 TileSize
- TileCodeSize
,
745 SmmSetMemoryAttributes (
746 mCpuHotPlugData
.SmBase
[mMaxNumberOfCpus
- 1] + SMM_HANDLER_OFFSET
,
750 SmmClearMemoryAttributes (
751 mCpuHotPlugData
.SmBase
[mMaxNumberOfCpus
- 1] + SMM_HANDLER_OFFSET
,
759 SmmClearMemoryAttributes (
760 mCpuHotPlugData
.SmBase
[mMaxNumberOfCpus
- 1] + SMM_HANDLER_OFFSET
+ TileCodeSize
,
761 SIZE_32KB
- TileCodeSize
,
764 SmmSetMemoryAttributes (
765 mCpuHotPlugData
.SmBase
[mMaxNumberOfCpus
- 1] + SMM_HANDLER_OFFSET
+ TileCodeSize
,
766 SIZE_32KB
- TileCodeSize
,
772 This function sets memory attribute according to MemoryAttributesTable.
775 SetMemMapAttributes (
779 EFI_MEMORY_DESCRIPTOR
*MemoryMap
;
780 EFI_MEMORY_DESCRIPTOR
*MemoryMapStart
;
781 UINTN MemoryMapEntryCount
;
782 UINTN DescriptorSize
;
784 EDKII_PI_SMM_MEMORY_ATTRIBUTES_TABLE
*MemoryAttributesTable
;
786 SmmGetSystemConfigurationTable (&gEdkiiPiSmmMemoryAttributesTableGuid
, (VOID
**)&MemoryAttributesTable
);
787 if (MemoryAttributesTable
== NULL
) {
788 DEBUG ((DEBUG_INFO
, "MemoryAttributesTable - NULL\n"));
792 DEBUG ((DEBUG_INFO
, "MemoryAttributesTable:\n"));
793 DEBUG ((DEBUG_INFO
, " Version - 0x%08x\n", MemoryAttributesTable
->Version
));
794 DEBUG ((DEBUG_INFO
, " NumberOfEntries - 0x%08x\n", MemoryAttributesTable
->NumberOfEntries
));
795 DEBUG ((DEBUG_INFO
, " DescriptorSize - 0x%08x\n", MemoryAttributesTable
->DescriptorSize
));
797 MemoryMapEntryCount
= MemoryAttributesTable
->NumberOfEntries
;
798 DescriptorSize
= MemoryAttributesTable
->DescriptorSize
;
799 MemoryMapStart
= (EFI_MEMORY_DESCRIPTOR
*)(MemoryAttributesTable
+ 1);
800 MemoryMap
= MemoryMapStart
;
801 for (Index
= 0; Index
< MemoryMapEntryCount
; Index
++) {
802 DEBUG ((DEBUG_INFO
, "Entry (0x%x)\n", MemoryMap
));
803 DEBUG ((DEBUG_INFO
, " Type - 0x%x\n", MemoryMap
->Type
));
804 DEBUG ((DEBUG_INFO
, " PhysicalStart - 0x%016lx\n", MemoryMap
->PhysicalStart
));
805 DEBUG ((DEBUG_INFO
, " VirtualStart - 0x%016lx\n", MemoryMap
->VirtualStart
));
806 DEBUG ((DEBUG_INFO
, " NumberOfPages - 0x%016lx\n", MemoryMap
->NumberOfPages
));
807 DEBUG ((DEBUG_INFO
, " Attribute - 0x%016lx\n", MemoryMap
->Attribute
));
808 MemoryMap
= NEXT_MEMORY_DESCRIPTOR(MemoryMap
, DescriptorSize
);
811 MemoryMap
= MemoryMapStart
;
812 for (Index
= 0; Index
< MemoryMapEntryCount
; Index
++) {
813 DEBUG ((DEBUG_VERBOSE
, "SetAttribute: Memory Entry - 0x%lx, 0x%x\n", MemoryMap
->PhysicalStart
, MemoryMap
->NumberOfPages
));
814 switch (MemoryMap
->Type
) {
815 case EfiRuntimeServicesCode
:
816 SmmSetMemoryAttributes (
817 MemoryMap
->PhysicalStart
,
818 EFI_PAGES_TO_SIZE((UINTN
)MemoryMap
->NumberOfPages
),
822 case EfiRuntimeServicesData
:
823 SmmSetMemoryAttributes (
824 MemoryMap
->PhysicalStart
,
825 EFI_PAGES_TO_SIZE((UINTN
)MemoryMap
->NumberOfPages
),
830 SmmSetMemoryAttributes (
831 MemoryMap
->PhysicalStart
,
832 EFI_PAGES_TO_SIZE((UINTN
)MemoryMap
->NumberOfPages
),
837 MemoryMap
= NEXT_MEMORY_DESCRIPTOR(MemoryMap
, DescriptorSize
);
840 PatchSmmSaveStateMap ();
847 Sort memory map entries based upon PhysicalStart, from low to high.
849 @param MemoryMap A pointer to the buffer in which firmware places
850 the current memory map.
851 @param MemoryMapSize Size, in bytes, of the MemoryMap buffer.
852 @param DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
857 IN OUT EFI_MEMORY_DESCRIPTOR
*MemoryMap
,
858 IN UINTN MemoryMapSize
,
859 IN UINTN DescriptorSize
862 EFI_MEMORY_DESCRIPTOR
*MemoryMapEntry
;
863 EFI_MEMORY_DESCRIPTOR
*NextMemoryMapEntry
;
864 EFI_MEMORY_DESCRIPTOR
*MemoryMapEnd
;
865 EFI_MEMORY_DESCRIPTOR TempMemoryMap
;
867 MemoryMapEntry
= MemoryMap
;
868 NextMemoryMapEntry
= NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry
, DescriptorSize
);
869 MemoryMapEnd
= (EFI_MEMORY_DESCRIPTOR
*) ((UINT8
*) MemoryMap
+ MemoryMapSize
);
870 while (MemoryMapEntry
< MemoryMapEnd
) {
871 while (NextMemoryMapEntry
< MemoryMapEnd
) {
872 if (MemoryMapEntry
->PhysicalStart
> NextMemoryMapEntry
->PhysicalStart
) {
873 CopyMem (&TempMemoryMap
, MemoryMapEntry
, sizeof(EFI_MEMORY_DESCRIPTOR
));
874 CopyMem (MemoryMapEntry
, NextMemoryMapEntry
, sizeof(EFI_MEMORY_DESCRIPTOR
));
875 CopyMem (NextMemoryMapEntry
, &TempMemoryMap
, sizeof(EFI_MEMORY_DESCRIPTOR
));
878 NextMemoryMapEntry
= NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry
, DescriptorSize
);
881 MemoryMapEntry
= NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry
, DescriptorSize
);
882 NextMemoryMapEntry
= NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry
, DescriptorSize
);
887 Return if a UEFI memory page should be marked as not present in SMM page table.
888 If the memory map entries type is
889 EfiLoaderCode/Data, EfiBootServicesCode/Data, EfiConventionalMemory,
890 EfiUnusableMemory, EfiACPIReclaimMemory, return TRUE.
893 @param[in] MemoryMap A pointer to the memory descriptor.
895 @return TRUE The memory described will be marked as not present in SMM page table.
896 @return FALSE The memory described will not be marked as not present in SMM page table.
899 IsUefiPageNotPresent (
900 IN EFI_MEMORY_DESCRIPTOR
*MemoryMap
903 switch (MemoryMap
->Type
) {
906 case EfiBootServicesCode
:
907 case EfiBootServicesData
:
908 case EfiConventionalMemory
:
909 case EfiUnusableMemory
:
910 case EfiACPIReclaimMemory
:
918 Merge continous memory map entries whose type is
919 EfiLoaderCode/Data, EfiBootServicesCode/Data, EfiConventionalMemory,
920 EfiUnusableMemory, EfiACPIReclaimMemory, because the memory described by
921 these entries will be set as NOT present in SMM page table.
923 @param[in, out] MemoryMap A pointer to the buffer in which firmware places
924 the current memory map.
925 @param[in, out] MemoryMapSize A pointer to the size, in bytes, of the
926 MemoryMap buffer. On input, this is the size of
927 the current memory map. On output,
928 it is the size of new memory map after merge.
929 @param[in] DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
933 MergeMemoryMapForNotPresentEntry (
934 IN OUT EFI_MEMORY_DESCRIPTOR
*MemoryMap
,
935 IN OUT UINTN
*MemoryMapSize
,
936 IN UINTN DescriptorSize
939 EFI_MEMORY_DESCRIPTOR
*MemoryMapEntry
;
940 EFI_MEMORY_DESCRIPTOR
*MemoryMapEnd
;
941 UINT64 MemoryBlockLength
;
942 EFI_MEMORY_DESCRIPTOR
*NewMemoryMapEntry
;
943 EFI_MEMORY_DESCRIPTOR
*NextMemoryMapEntry
;
945 MemoryMapEntry
= MemoryMap
;
946 NewMemoryMapEntry
= MemoryMap
;
947 MemoryMapEnd
= (EFI_MEMORY_DESCRIPTOR
*) ((UINT8
*) MemoryMap
+ *MemoryMapSize
);
948 while ((UINTN
)MemoryMapEntry
< (UINTN
)MemoryMapEnd
) {
949 CopyMem (NewMemoryMapEntry
, MemoryMapEntry
, sizeof(EFI_MEMORY_DESCRIPTOR
));
950 NextMemoryMapEntry
= NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry
, DescriptorSize
);
953 MemoryBlockLength
= (UINT64
) (EFI_PAGES_TO_SIZE((UINTN
)MemoryMapEntry
->NumberOfPages
));
954 if (((UINTN
)NextMemoryMapEntry
< (UINTN
)MemoryMapEnd
) &&
955 IsUefiPageNotPresent(MemoryMapEntry
) && IsUefiPageNotPresent(NextMemoryMapEntry
) &&
956 ((MemoryMapEntry
->PhysicalStart
+ MemoryBlockLength
) == NextMemoryMapEntry
->PhysicalStart
)) {
957 MemoryMapEntry
->NumberOfPages
+= NextMemoryMapEntry
->NumberOfPages
;
958 if (NewMemoryMapEntry
!= MemoryMapEntry
) {
959 NewMemoryMapEntry
->NumberOfPages
+= NextMemoryMapEntry
->NumberOfPages
;
962 NextMemoryMapEntry
= NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry
, DescriptorSize
);
965 MemoryMapEntry
= PREVIOUS_MEMORY_DESCRIPTOR (NextMemoryMapEntry
, DescriptorSize
);
970 MemoryMapEntry
= NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry
, DescriptorSize
);
971 NewMemoryMapEntry
= NEXT_MEMORY_DESCRIPTOR (NewMemoryMapEntry
, DescriptorSize
);
974 *MemoryMapSize
= (UINTN
)NewMemoryMapEntry
- (UINTN
)MemoryMap
;
980 This function caches the UEFI memory map information.
989 UINT32 DescriptorVersion
;
990 EFI_MEMORY_DESCRIPTOR
*MemoryMap
;
991 UINTN UefiMemoryMapSize
;
993 DEBUG ((DEBUG_INFO
, "GetUefiMemoryMap\n"));
995 UefiMemoryMapSize
= 0;
997 Status
= gBS
->GetMemoryMap (
1001 &mUefiDescriptorSize
,
1004 ASSERT (Status
== EFI_BUFFER_TOO_SMALL
);
1007 Status
= gBS
->AllocatePool (EfiBootServicesData
, UefiMemoryMapSize
, (VOID
**)&MemoryMap
);
1008 ASSERT (MemoryMap
!= NULL
);
1009 if (MemoryMap
== NULL
) {
1013 Status
= gBS
->GetMemoryMap (
1017 &mUefiDescriptorSize
,
1020 if (EFI_ERROR (Status
)) {
1021 gBS
->FreePool (MemoryMap
);
1024 } while (Status
== EFI_BUFFER_TOO_SMALL
);
1026 if (MemoryMap
== NULL
) {
1030 SortMemoryMap (MemoryMap
, UefiMemoryMapSize
, mUefiDescriptorSize
);
1031 MergeMemoryMapForNotPresentEntry (MemoryMap
, &UefiMemoryMapSize
, mUefiDescriptorSize
);
1033 mUefiMemoryMapSize
= UefiMemoryMapSize
;
1034 mUefiMemoryMap
= AllocateCopyPool (UefiMemoryMapSize
, MemoryMap
);
1035 ASSERT (mUefiMemoryMap
!= NULL
);
1037 gBS
->FreePool (MemoryMap
);
1041 This function sets UEFI memory attribute according to UEFI memory map.
1043 The normal memory region is marked as not present, such as
1044 EfiLoaderCode/Data, EfiBootServicesCode/Data, EfiConventionalMemory,
1045 EfiUnusableMemory, EfiACPIReclaimMemory.
1048 SetUefiMemMapAttributes (
1053 EFI_MEMORY_DESCRIPTOR
*MemoryMap
;
1054 UINTN MemoryMapEntryCount
;
1057 DEBUG ((DEBUG_INFO
, "SetUefiMemMapAttributes\n"));
1059 if (mUefiMemoryMap
== NULL
) {
1060 DEBUG ((DEBUG_INFO
, "UefiMemoryMap - NULL\n"));
1064 MemoryMapEntryCount
= mUefiMemoryMapSize
/mUefiDescriptorSize
;
1065 MemoryMap
= mUefiMemoryMap
;
1066 for (Index
= 0; Index
< MemoryMapEntryCount
; Index
++) {
1067 if (IsUefiPageNotPresent(MemoryMap
)) {
1068 Status
= SmmSetMemoryAttributes (
1069 MemoryMap
->PhysicalStart
,
1070 EFI_PAGES_TO_SIZE((UINTN
)MemoryMap
->NumberOfPages
),
1075 "UefiMemory protection: 0x%lx - 0x%lx %r\n",
1076 MemoryMap
->PhysicalStart
,
1077 MemoryMap
->PhysicalStart
+ (UINT64
)EFI_PAGES_TO_SIZE((UINTN
)MemoryMap
->NumberOfPages
),
1081 MemoryMap
= NEXT_MEMORY_DESCRIPTOR(MemoryMap
, mUefiDescriptorSize
);
1085 // Do free mUefiMemoryMap, it will be checked in IsSmmCommBufferForbiddenAddress().
1090 Return if the Address is forbidden as SMM communication buffer.
1092 @param[in] Address the address to be checked
1094 @return TRUE The address is forbidden as SMM communication buffer.
1095 @return FALSE The address is allowed as SMM communication buffer.
1098 IsSmmCommBufferForbiddenAddress (
1102 EFI_MEMORY_DESCRIPTOR
*MemoryMap
;
1103 UINTN MemoryMapEntryCount
;
1106 if (mUefiMemoryMap
== NULL
) {
1110 MemoryMap
= mUefiMemoryMap
;
1111 MemoryMapEntryCount
= mUefiMemoryMapSize
/mUefiDescriptorSize
;
1112 for (Index
= 0; Index
< MemoryMapEntryCount
; Index
++) {
1113 if (IsUefiPageNotPresent (MemoryMap
)) {
1114 if ((Address
>= MemoryMap
->PhysicalStart
) &&
1115 (Address
< MemoryMap
->PhysicalStart
+ EFI_PAGES_TO_SIZE((UINTN
)MemoryMap
->NumberOfPages
)) ) {
1119 MemoryMap
= NEXT_MEMORY_DESCRIPTOR(MemoryMap
, mUefiDescriptorSize
);