3 Copyright (c) 2016, 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
] & 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
] & 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
] & 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
+ ((*PageEntry
) & PAGE_PROGATE_BITS
);
309 (*PageEntry
) = (UINT64
)(UINTN
)NewPageEntry
+ 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
+ IA32_PG_PS
+ ((*PageEntry
) & PAGE_PROGATE_BITS
);
330 (*PageEntry
) = (UINT64
)(UINTN
)NewPageEntry
+ 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
;
384 ASSERT (Attributes
!= 0);
385 ASSERT ((Attributes
& ~(EFI_MEMORY_RP
| EFI_MEMORY_RO
| EFI_MEMORY_XP
)) == 0);
387 ASSERT ((BaseAddress
& (SIZE_4KB
- 1)) == 0);
388 ASSERT ((Length
& (SIZE_4KB
- 1)) == 0);
391 return RETURN_INVALID_PARAMETER
;
394 // DEBUG ((DEBUG_ERROR, "ConvertMemoryPageAttributes(%x) - %016lx, %016lx, %02lx\n", IsSet, BaseAddress, Length, Attributes));
396 if (IsSplitted
!= NULL
) {
399 if (IsModified
!= NULL
) {
404 // Below logic is to check 2M/4K page to make sure we donot waist memory.
406 while (Length
!= 0) {
407 PageEntry
= GetPageTableEntry (BaseAddress
, &PageAttribute
);
408 if (PageEntry
== NULL
) {
409 return RETURN_UNSUPPORTED
;
411 PageEntryLength
= PageAttributeToLength (PageAttribute
);
412 SplitAttribute
= NeedSplitPage (BaseAddress
, Length
, PageEntry
, PageAttribute
);
413 if (SplitAttribute
== PageNone
) {
414 ConvertPageEntryAttribute (PageEntry
, Attributes
, IsSet
, &IsEntryModified
);
415 if (IsEntryModified
) {
416 if (IsModified
!= NULL
) {
421 // Convert success, move to next
423 BaseAddress
+= PageEntryLength
;
424 Length
-= PageEntryLength
;
426 Status
= SplitPage (PageEntry
, PageAttribute
, SplitAttribute
);
427 if (RETURN_ERROR (Status
)) {
428 return RETURN_UNSUPPORTED
;
430 if (IsSplitted
!= NULL
) {
433 if (IsModified
!= NULL
) {
437 // Just split current page
438 // Convert success in next around
443 return RETURN_SUCCESS
;
447 FlushTlb on current processor.
449 @param[in,out] Buffer Pointer to private data buffer.
453 FlushTlbOnCurrentProcessor (
461 FlushTlb for all processors.
470 FlushTlbOnCurrentProcessor (NULL
);
472 for (Index
= 0; Index
< gSmst
->NumberOfCpus
; Index
++) {
473 if (Index
!= gSmst
->CurrentlyExecutingCpu
) {
474 // Force to start up AP in blocking mode,
475 SmmBlockingStartupThisAp (FlushTlbOnCurrentProcessor
, Index
, NULL
);
476 // Do not check return status, because AP might not be present in some corner cases.
482 This function sets the attributes for the memory region specified by BaseAddress and
483 Length from their current attributes to the attributes specified by Attributes.
485 @param[in] BaseAddress The physical address that is the start address of a memory region.
486 @param[in] Length The size in bytes of the memory region.
487 @param[in] Attributes The bit mask of attributes to set for the memory region.
488 @param[out] IsSplitted TRUE means page table splitted. FALSE means page table not splitted.
490 @retval EFI_SUCCESS The attributes were set for the memory region.
491 @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
492 BaseAddress and Length cannot be modified.
493 @retval EFI_INVALID_PARAMETER Length is zero.
494 Attributes specified an illegal combination of attributes that
495 cannot be set together.
496 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
497 the memory resource range.
498 @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
499 resource range specified by BaseAddress and Length.
500 The bit mask of attributes is not support for the memory resource
501 range specified by BaseAddress and Length.
506 SmmSetMemoryAttributesEx (
507 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
509 IN UINT64 Attributes
,
510 OUT BOOLEAN
*IsSplitted OPTIONAL
516 Status
= ConvertMemoryPageAttributes (BaseAddress
, Length
, Attributes
, TRUE
, IsSplitted
, &IsModified
);
517 if (!EFI_ERROR(Status
)) {
520 // Flush TLB as last step
530 This function clears the attributes for the memory region specified by BaseAddress and
531 Length from their current attributes to the attributes specified by Attributes.
533 @param[in] BaseAddress The physical address that is the start address of a memory region.
534 @param[in] Length The size in bytes of the memory region.
535 @param[in] Attributes The bit mask of attributes to clear for the memory region.
536 @param[out] IsSplitted TRUE means page table splitted. FALSE means page table not splitted.
538 @retval EFI_SUCCESS The attributes were cleared for the memory region.
539 @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
540 BaseAddress and Length cannot be modified.
541 @retval EFI_INVALID_PARAMETER Length is zero.
542 Attributes specified an illegal combination of attributes that
543 cannot be set together.
544 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
545 the memory resource range.
546 @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
547 resource range specified by BaseAddress and Length.
548 The bit mask of attributes is not support for the memory resource
549 range specified by BaseAddress and Length.
554 SmmClearMemoryAttributesEx (
555 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
557 IN UINT64 Attributes
,
558 OUT BOOLEAN
*IsSplitted OPTIONAL
564 Status
= ConvertMemoryPageAttributes (BaseAddress
, Length
, Attributes
, FALSE
, IsSplitted
, &IsModified
);
565 if (!EFI_ERROR(Status
)) {
568 // Flush TLB as last step
578 This function sets the attributes for the memory region specified by BaseAddress and
579 Length from their current attributes to the attributes specified by Attributes.
581 @param[in] BaseAddress The physical address that is the start address of a memory region.
582 @param[in] Length The size in bytes of the memory region.
583 @param[in] Attributes The bit mask of attributes to set for the memory region.
585 @retval EFI_SUCCESS The attributes were set for the memory region.
586 @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
587 BaseAddress and Length cannot be modified.
588 @retval EFI_INVALID_PARAMETER Length is zero.
589 Attributes specified an illegal combination of attributes that
590 cannot be set together.
591 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
592 the memory resource range.
593 @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
594 resource range specified by BaseAddress and Length.
595 The bit mask of attributes is not support for the memory resource
596 range specified by BaseAddress and Length.
601 SmmSetMemoryAttributes (
602 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
607 return SmmSetMemoryAttributesEx (BaseAddress
, Length
, Attributes
, NULL
);
611 This function clears the attributes for the memory region specified by BaseAddress and
612 Length from their current attributes to the attributes specified by Attributes.
614 @param[in] BaseAddress The physical address that is the start address of a memory region.
615 @param[in] Length The size in bytes of the memory region.
616 @param[in] Attributes The bit mask of attributes to clear for the memory region.
618 @retval EFI_SUCCESS The attributes were cleared for the memory region.
619 @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
620 BaseAddress and Length cannot be modified.
621 @retval EFI_INVALID_PARAMETER Length is zero.
622 Attributes specified an illegal combination of attributes that
623 cannot be set together.
624 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
625 the memory resource range.
626 @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
627 resource range specified by BaseAddress and Length.
628 The bit mask of attributes is not support for the memory resource
629 range specified by BaseAddress and Length.
634 SmmClearMemoryAttributes (
635 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
640 return SmmClearMemoryAttributesEx (BaseAddress
, Length
, Attributes
, NULL
);
646 Retrieves a pointer to the system configuration table from the SMM System Table
647 based on a specified GUID.
649 @param[in] TableGuid The pointer to table's GUID type.
650 @param[out] Table The pointer to the table associated with TableGuid in the EFI System Table.
652 @retval EFI_SUCCESS A configuration table matching TableGuid was found.
653 @retval EFI_NOT_FOUND A configuration table matching TableGuid could not be found.
658 SmmGetSystemConfigurationTable (
659 IN EFI_GUID
*TableGuid
,
665 ASSERT (TableGuid
!= NULL
);
666 ASSERT (Table
!= NULL
);
669 for (Index
= 0; Index
< gSmst
->NumberOfTableEntries
; Index
++) {
670 if (CompareGuid (TableGuid
, &(gSmst
->SmmConfigurationTable
[Index
].VendorGuid
))) {
671 *Table
= gSmst
->SmmConfigurationTable
[Index
].VendorTable
;
676 return EFI_NOT_FOUND
;
680 This function sets SMM save state buffer to be RW and XP.
683 PatchSmmSaveStateMap (
692 TileCodeSize
= GetSmiHandlerSize ();
693 TileCodeSize
= ALIGN_VALUE(TileCodeSize
, SIZE_4KB
);
694 TileDataSize
= (SMRAM_SAVE_STATE_MAP_OFFSET
- SMM_PSD_OFFSET
) + sizeof (SMRAM_SAVE_STATE_MAP
);
695 TileDataSize
= ALIGN_VALUE(TileDataSize
, SIZE_4KB
);
696 TileSize
= TileDataSize
+ TileCodeSize
- 1;
697 TileSize
= 2 * GetPowerOfTwo32 ((UINT32
)TileSize
);
699 DEBUG ((DEBUG_INFO
, "PatchSmmSaveStateMap:\n"));
700 for (Index
= 0; Index
< mMaxNumberOfCpus
- 1; Index
++) {
704 SmmSetMemoryAttributes (
705 mCpuHotPlugData
.SmBase
[Index
] + SMM_HANDLER_OFFSET
,
709 SmmClearMemoryAttributes (
710 mCpuHotPlugData
.SmBase
[Index
] + SMM_HANDLER_OFFSET
,
718 SmmClearMemoryAttributes (
719 mCpuHotPlugData
.SmBase
[Index
] + SMM_HANDLER_OFFSET
+ TileCodeSize
,
720 TileSize
- TileCodeSize
,
723 SmmSetMemoryAttributes (
724 mCpuHotPlugData
.SmBase
[Index
] + SMM_HANDLER_OFFSET
+ TileCodeSize
,
725 TileSize
- TileCodeSize
,
733 SmmSetMemoryAttributes (
734 mCpuHotPlugData
.SmBase
[mMaxNumberOfCpus
- 1] + SMM_HANDLER_OFFSET
,
738 SmmClearMemoryAttributes (
739 mCpuHotPlugData
.SmBase
[mMaxNumberOfCpus
- 1] + SMM_HANDLER_OFFSET
,
747 SmmClearMemoryAttributes (
748 mCpuHotPlugData
.SmBase
[mMaxNumberOfCpus
- 1] + SMM_HANDLER_OFFSET
+ TileCodeSize
,
749 SIZE_32KB
- TileCodeSize
,
752 SmmSetMemoryAttributes (
753 mCpuHotPlugData
.SmBase
[mMaxNumberOfCpus
- 1] + SMM_HANDLER_OFFSET
+ TileCodeSize
,
754 SIZE_32KB
- TileCodeSize
,
760 This function sets memory attribute according to MemoryAttributesTable.
763 SetMemMapAttributes (
767 EFI_MEMORY_DESCRIPTOR
*MemoryMap
;
768 EFI_MEMORY_DESCRIPTOR
*MemoryMapStart
;
769 UINTN MemoryMapEntryCount
;
770 UINTN DescriptorSize
;
772 EDKII_PI_SMM_MEMORY_ATTRIBUTES_TABLE
*MemoryAttributesTable
;
774 SmmGetSystemConfigurationTable (&gEdkiiPiSmmMemoryAttributesTableGuid
, (VOID
**)&MemoryAttributesTable
);
775 if (MemoryAttributesTable
== NULL
) {
776 DEBUG ((DEBUG_INFO
, "MemoryAttributesTable - NULL\n"));
780 DEBUG ((DEBUG_INFO
, "MemoryAttributesTable:\n"));
781 DEBUG ((DEBUG_INFO
, " Version - 0x%08x\n", MemoryAttributesTable
->Version
));
782 DEBUG ((DEBUG_INFO
, " NumberOfEntries - 0x%08x\n", MemoryAttributesTable
->NumberOfEntries
));
783 DEBUG ((DEBUG_INFO
, " DescriptorSize - 0x%08x\n", MemoryAttributesTable
->DescriptorSize
));
785 MemoryMapEntryCount
= MemoryAttributesTable
->NumberOfEntries
;
786 DescriptorSize
= MemoryAttributesTable
->DescriptorSize
;
787 MemoryMapStart
= (EFI_MEMORY_DESCRIPTOR
*)(MemoryAttributesTable
+ 1);
788 MemoryMap
= MemoryMapStart
;
789 for (Index
= 0; Index
< MemoryMapEntryCount
; Index
++) {
790 DEBUG ((DEBUG_INFO
, "Entry (0x%x)\n", MemoryMap
));
791 DEBUG ((DEBUG_INFO
, " Type - 0x%x\n", MemoryMap
->Type
));
792 DEBUG ((DEBUG_INFO
, " PhysicalStart - 0x%016lx\n", MemoryMap
->PhysicalStart
));
793 DEBUG ((DEBUG_INFO
, " VirtualStart - 0x%016lx\n", MemoryMap
->VirtualStart
));
794 DEBUG ((DEBUG_INFO
, " NumberOfPages - 0x%016lx\n", MemoryMap
->NumberOfPages
));
795 DEBUG ((DEBUG_INFO
, " Attribute - 0x%016lx\n", MemoryMap
->Attribute
));
796 MemoryMap
= NEXT_MEMORY_DESCRIPTOR(MemoryMap
, DescriptorSize
);
799 MemoryMap
= MemoryMapStart
;
800 for (Index
= 0; Index
< MemoryMapEntryCount
; Index
++) {
801 DEBUG ((DEBUG_VERBOSE
, "SetAttribute: Memory Entry - 0x%lx, 0x%x\n", MemoryMap
->PhysicalStart
, MemoryMap
->NumberOfPages
));
802 switch (MemoryMap
->Type
) {
803 case EfiRuntimeServicesCode
:
804 SmmSetMemoryAttributes (
805 MemoryMap
->PhysicalStart
,
806 EFI_PAGES_TO_SIZE((UINTN
)MemoryMap
->NumberOfPages
),
810 case EfiRuntimeServicesData
:
811 SmmSetMemoryAttributes (
812 MemoryMap
->PhysicalStart
,
813 EFI_PAGES_TO_SIZE((UINTN
)MemoryMap
->NumberOfPages
),
818 SmmSetMemoryAttributes (
819 MemoryMap
->PhysicalStart
,
820 EFI_PAGES_TO_SIZE((UINTN
)MemoryMap
->NumberOfPages
),
825 MemoryMap
= NEXT_MEMORY_DESCRIPTOR(MemoryMap
, DescriptorSize
);
828 PatchSmmSaveStateMap ();
835 Sort memory map entries based upon PhysicalStart, from low to high.
837 @param MemoryMap A pointer to the buffer in which firmware places
838 the current memory map.
839 @param MemoryMapSize Size, in bytes, of the MemoryMap buffer.
840 @param DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
845 IN OUT EFI_MEMORY_DESCRIPTOR
*MemoryMap
,
846 IN UINTN MemoryMapSize
,
847 IN UINTN DescriptorSize
850 EFI_MEMORY_DESCRIPTOR
*MemoryMapEntry
;
851 EFI_MEMORY_DESCRIPTOR
*NextMemoryMapEntry
;
852 EFI_MEMORY_DESCRIPTOR
*MemoryMapEnd
;
853 EFI_MEMORY_DESCRIPTOR TempMemoryMap
;
855 MemoryMapEntry
= MemoryMap
;
856 NextMemoryMapEntry
= NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry
, DescriptorSize
);
857 MemoryMapEnd
= (EFI_MEMORY_DESCRIPTOR
*) ((UINT8
*) MemoryMap
+ MemoryMapSize
);
858 while (MemoryMapEntry
< MemoryMapEnd
) {
859 while (NextMemoryMapEntry
< MemoryMapEnd
) {
860 if (MemoryMapEntry
->PhysicalStart
> NextMemoryMapEntry
->PhysicalStart
) {
861 CopyMem (&TempMemoryMap
, MemoryMapEntry
, sizeof(EFI_MEMORY_DESCRIPTOR
));
862 CopyMem (MemoryMapEntry
, NextMemoryMapEntry
, sizeof(EFI_MEMORY_DESCRIPTOR
));
863 CopyMem (NextMemoryMapEntry
, &TempMemoryMap
, sizeof(EFI_MEMORY_DESCRIPTOR
));
866 NextMemoryMapEntry
= NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry
, DescriptorSize
);
869 MemoryMapEntry
= NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry
, DescriptorSize
);
870 NextMemoryMapEntry
= NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry
, DescriptorSize
);
875 Return if a UEFI memory page should be marked as not present in SMM page table.
876 If the memory map entries type is
877 EfiLoaderCode/Data, EfiBootServicesCode/Data, EfiConventionalMemory,
878 EfiUnusableMemory, EfiACPIReclaimMemory, return TRUE.
881 @param[in] MemoryMap A pointer to the memory descriptor.
883 @return TRUE The memory described will be marked as not present in SMM page table.
884 @return FALSE The memory described will not be marked as not present in SMM page table.
887 IsUefiPageNotPresent (
888 IN EFI_MEMORY_DESCRIPTOR
*MemoryMap
891 switch (MemoryMap
->Type
) {
894 case EfiBootServicesCode
:
895 case EfiBootServicesData
:
896 case EfiConventionalMemory
:
897 case EfiUnusableMemory
:
898 case EfiACPIReclaimMemory
:
906 Merge continous memory map entries whose type is
907 EfiLoaderCode/Data, EfiBootServicesCode/Data, EfiConventionalMemory,
908 EfiUnusableMemory, EfiACPIReclaimMemory, because the memory described by
909 these entries will be set as NOT present in SMM page table.
911 @param[in, out] MemoryMap A pointer to the buffer in which firmware places
912 the current memory map.
913 @param[in, out] MemoryMapSize A pointer to the size, in bytes, of the
914 MemoryMap buffer. On input, this is the size of
915 the current memory map. On output,
916 it is the size of new memory map after merge.
917 @param[in] DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
921 MergeMemoryMapForNotPresentEntry (
922 IN OUT EFI_MEMORY_DESCRIPTOR
*MemoryMap
,
923 IN OUT UINTN
*MemoryMapSize
,
924 IN UINTN DescriptorSize
927 EFI_MEMORY_DESCRIPTOR
*MemoryMapEntry
;
928 EFI_MEMORY_DESCRIPTOR
*MemoryMapEnd
;
929 UINT64 MemoryBlockLength
;
930 EFI_MEMORY_DESCRIPTOR
*NewMemoryMapEntry
;
931 EFI_MEMORY_DESCRIPTOR
*NextMemoryMapEntry
;
933 MemoryMapEntry
= MemoryMap
;
934 NewMemoryMapEntry
= MemoryMap
;
935 MemoryMapEnd
= (EFI_MEMORY_DESCRIPTOR
*) ((UINT8
*) MemoryMap
+ *MemoryMapSize
);
936 while ((UINTN
)MemoryMapEntry
< (UINTN
)MemoryMapEnd
) {
937 CopyMem (NewMemoryMapEntry
, MemoryMapEntry
, sizeof(EFI_MEMORY_DESCRIPTOR
));
938 NextMemoryMapEntry
= NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry
, DescriptorSize
);
941 MemoryBlockLength
= (UINT64
) (EFI_PAGES_TO_SIZE((UINTN
)MemoryMapEntry
->NumberOfPages
));
942 if (((UINTN
)NextMemoryMapEntry
< (UINTN
)MemoryMapEnd
) &&
943 IsUefiPageNotPresent(MemoryMapEntry
) && IsUefiPageNotPresent(NextMemoryMapEntry
) &&
944 ((MemoryMapEntry
->PhysicalStart
+ MemoryBlockLength
) == NextMemoryMapEntry
->PhysicalStart
)) {
945 MemoryMapEntry
->NumberOfPages
+= NextMemoryMapEntry
->NumberOfPages
;
946 if (NewMemoryMapEntry
!= MemoryMapEntry
) {
947 NewMemoryMapEntry
->NumberOfPages
+= NextMemoryMapEntry
->NumberOfPages
;
950 NextMemoryMapEntry
= NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry
, DescriptorSize
);
953 MemoryMapEntry
= PREVIOUS_MEMORY_DESCRIPTOR (NextMemoryMapEntry
, DescriptorSize
);
958 MemoryMapEntry
= NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry
, DescriptorSize
);
959 NewMemoryMapEntry
= NEXT_MEMORY_DESCRIPTOR (NewMemoryMapEntry
, DescriptorSize
);
962 *MemoryMapSize
= (UINTN
)NewMemoryMapEntry
- (UINTN
)MemoryMap
;
968 This function caches the UEFI memory map information.
977 UINT32 DescriptorVersion
;
978 EFI_MEMORY_DESCRIPTOR
*MemoryMap
;
979 UINTN UefiMemoryMapSize
;
981 DEBUG ((DEBUG_INFO
, "GetUefiMemoryMap\n"));
983 UefiMemoryMapSize
= 0;
985 Status
= gBS
->GetMemoryMap (
989 &mUefiDescriptorSize
,
992 ASSERT (Status
== EFI_BUFFER_TOO_SMALL
);
995 Status
= gBS
->AllocatePool (EfiBootServicesData
, UefiMemoryMapSize
, (VOID
**)&MemoryMap
);
996 ASSERT (MemoryMap
!= NULL
);
997 if (MemoryMap
== NULL
) {
1001 Status
= gBS
->GetMemoryMap (
1005 &mUefiDescriptorSize
,
1008 if (EFI_ERROR (Status
)) {
1009 gBS
->FreePool (MemoryMap
);
1012 } while (Status
== EFI_BUFFER_TOO_SMALL
);
1014 if (MemoryMap
== NULL
) {
1018 SortMemoryMap (MemoryMap
, UefiMemoryMapSize
, mUefiDescriptorSize
);
1019 MergeMemoryMapForNotPresentEntry (MemoryMap
, &UefiMemoryMapSize
, mUefiDescriptorSize
);
1021 mUefiMemoryMapSize
= UefiMemoryMapSize
;
1022 mUefiMemoryMap
= AllocateCopyPool (UefiMemoryMapSize
, MemoryMap
);
1023 ASSERT (mUefiMemoryMap
!= NULL
);
1025 gBS
->FreePool (MemoryMap
);
1029 This function sets UEFI memory attribute according to UEFI memory map.
1031 The normal memory region is marked as not present, such as
1032 EfiLoaderCode/Data, EfiBootServicesCode/Data, EfiConventionalMemory,
1033 EfiUnusableMemory, EfiACPIReclaimMemory.
1036 SetUefiMemMapAttributes (
1040 EFI_MEMORY_DESCRIPTOR
*MemoryMap
;
1041 UINTN MemoryMapEntryCount
;
1044 DEBUG ((DEBUG_INFO
, "SetUefiMemMapAttributes\n"));
1046 if (mUefiMemoryMap
== NULL
) {
1047 DEBUG ((DEBUG_INFO
, "UefiMemoryMap - NULL\n"));
1051 MemoryMapEntryCount
= mUefiMemoryMapSize
/mUefiDescriptorSize
;
1052 MemoryMap
= mUefiMemoryMap
;
1053 for (Index
= 0; Index
< MemoryMapEntryCount
; Index
++) {
1054 if (IsUefiPageNotPresent(MemoryMap
)) {
1055 DEBUG ((DEBUG_INFO
, "UefiMemory protection: 0x%lx - 0x%lx\n", MemoryMap
->PhysicalStart
, MemoryMap
->PhysicalStart
+ (UINT64
)EFI_PAGES_TO_SIZE((UINTN
)MemoryMap
->NumberOfPages
)));
1056 SmmSetMemoryAttributes (
1057 MemoryMap
->PhysicalStart
,
1058 EFI_PAGES_TO_SIZE((UINTN
)MemoryMap
->NumberOfPages
),
1062 MemoryMap
= NEXT_MEMORY_DESCRIPTOR(MemoryMap
, mUefiDescriptorSize
);
1066 // Do free mUefiMemoryMap, it will be checked in IsSmmCommBufferForbiddenAddress().
1071 Return if the Address is forbidden as SMM communication buffer.
1073 @param[in] Address the address to be checked
1075 @return TRUE The address is forbidden as SMM communication buffer.
1076 @return FALSE The address is allowed as SMM communication buffer.
1079 IsSmmCommBufferForbiddenAddress (
1083 EFI_MEMORY_DESCRIPTOR
*MemoryMap
;
1084 UINTN MemoryMapEntryCount
;
1087 if (mUefiMemoryMap
== NULL
) {
1091 MemoryMap
= mUefiMemoryMap
;
1092 MemoryMapEntryCount
= mUefiMemoryMapSize
/mUefiDescriptorSize
;
1093 for (Index
= 0; Index
< MemoryMapEntryCount
; Index
++) {
1094 if (IsUefiPageNotPresent (MemoryMap
)) {
1095 if ((Address
>= MemoryMap
->PhysicalStart
) &&
1096 (Address
< MemoryMap
->PhysicalStart
+ EFI_PAGES_TO_SIZE((UINTN
)MemoryMap
->NumberOfPages
)) ) {
1100 MemoryMap
= NEXT_MEMORY_DESCRIPTOR(MemoryMap
, mUefiDescriptorSize
);