mirror of
https://github.com/acidanthera/audk.git
synced 2025-04-08 17:05:09 +02:00
UefiCpuPkg/PiSmmCpuDxeSmm: Refine DxeSmm PageTable update logic
This patch is to refine the updatePageTable logic for DxeSmm. For DxeSmm, PageTable will be updated in the first SMI when SMM ready to lock happen: IF SMM Profile is TRUE: 1. Mark mProtectionMemRange attribute: SmrrBase:Present, SMM profile base:Present&Nx, MMRAM ranges:Present, MMIO ranges: Present&Nx. 2. Mark the ranges not in mProtectionMemRange as RP (non-present). IF SMM Profile is FALSE: 1. Mark Non-MMRAM ranges as NX. 2. IF RestrictedMemoryAccess is TRUE: Forbidden Address mark as RP (IsUefiPageNotPresent is TRUE). Signed-off-by: Jiaxin Wu <jiaxin.wu@intel.com> Cc: Ray Ni <ray.ni@intel.com> Cc: Rahul Kumar <rahul1.kumar@intel.com> Cc: Gerd Hoffmann <kraxel@redhat.com> Cc: Star Zeng <star.zeng@intel.com> Cc: Dun Tan <dun.tan@intel.com> Cc: Hongbin1 Zhang <hongbin1.zhang@intel.com> Cc: Wei6 Xu <wei6.xu@intel.com> Cc: Yuanhao Xie <yuanhao.xie@intel.com>
This commit is contained in:
parent
5bcf6049f2
commit
1816c78f43
@ -311,116 +311,170 @@ GetUefiMemoryMap (
|
||||
}
|
||||
|
||||
/**
|
||||
This function sets UEFI memory attribute according to UEFI memory map.
|
||||
This function updates UEFI memory attribute according to UEFI memory map.
|
||||
|
||||
The normal memory region is marked as not present, such as
|
||||
EfiLoaderCode/Data, EfiBootServicesCode/Data, EfiConventionalMemory,
|
||||
EfiUnusableMemory, EfiACPIReclaimMemory.
|
||||
**/
|
||||
VOID
|
||||
SetUefiMemMapAttributes (
|
||||
UpdateUefiMemMapAttributes (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
EFI_MEMORY_DESCRIPTOR *MemoryMap;
|
||||
UINTN MemoryMapEntryCount;
|
||||
UINTN Index;
|
||||
EFI_MEMORY_DESCRIPTOR *Entry;
|
||||
BOOLEAN WriteProtect;
|
||||
BOOLEAN CetEnabled;
|
||||
EFI_STATUS Status;
|
||||
UINTN Index;
|
||||
UINT64 Limit;
|
||||
UINT64 PreviousAddress;
|
||||
UINTN PageTable;
|
||||
UINT64 Base;
|
||||
EFI_MEMORY_DESCRIPTOR *MemoryMap;
|
||||
UINTN MemoryMapEntryCount;
|
||||
EFI_MEMORY_DESCRIPTOR *Entry;
|
||||
|
||||
PERF_FUNCTION_BEGIN ();
|
||||
|
||||
DEBUG ((DEBUG_INFO, "SetUefiMemMapAttributes\n"));
|
||||
DEBUG ((DEBUG_INFO, "UpdateUefiMemMapAttributes Start...\n"));
|
||||
|
||||
WRITE_UNPROTECT_RO_PAGES (WriteProtect, CetEnabled);
|
||||
|
||||
if (mUefiMemoryMap != NULL) {
|
||||
MemoryMapEntryCount = mUefiMemoryMapSize/mUefiDescriptorSize;
|
||||
MemoryMap = mUefiMemoryMap;
|
||||
for (Index = 0; Index < MemoryMapEntryCount; Index++) {
|
||||
if (IsUefiPageNotPresent (MemoryMap)) {
|
||||
Status = SmmSetMemoryAttributes (
|
||||
MemoryMap->PhysicalStart,
|
||||
EFI_PAGES_TO_SIZE ((UINTN)MemoryMap->NumberOfPages),
|
||||
EFI_MEMORY_RP
|
||||
);
|
||||
DEBUG ((
|
||||
DEBUG_INFO,
|
||||
"UefiMemory protection: 0x%lx - 0x%lx %r\n",
|
||||
MemoryMap->PhysicalStart,
|
||||
MemoryMap->PhysicalStart + (UINT64)EFI_PAGES_TO_SIZE ((UINTN)MemoryMap->NumberOfPages),
|
||||
Status
|
||||
));
|
||||
}
|
||||
PageTable = AsmReadCr3 ();
|
||||
Limit = LShiftU64 (1, mPhysicalAddressBits);
|
||||
|
||||
MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, mUefiDescriptorSize);
|
||||
//
|
||||
// [0, 4k] may be non-present.
|
||||
//
|
||||
PreviousAddress = ((FixedPcdGet8 (PcdNullPointerDetectionPropertyMask) & BIT1) != 0) ? BASE_4KB : 0;
|
||||
|
||||
//
|
||||
// NonMmram shall be non-executable after the SmmReadyToLock event occurs, regardless of whether
|
||||
// RestrictedMemoryAccess is enabled, since all MM drivers located in NonMmram have already been dispatched and executed.
|
||||
//
|
||||
for (Index = 0; Index < mSmmCpuSmramRangeCount; Index++) {
|
||||
Base = mSmmCpuSmramRanges[Index].CpuStart;
|
||||
if (Base > PreviousAddress) {
|
||||
Status = ConvertMemoryPageAttributes (PageTable, mPagingMode, PreviousAddress, Base - PreviousAddress, EFI_MEMORY_XP, TRUE, NULL);
|
||||
ASSERT_RETURN_ERROR (Status);
|
||||
}
|
||||
|
||||
PreviousAddress = mSmmCpuSmramRanges[Index].CpuStart + mSmmCpuSmramRanges[Index].PhysicalSize;
|
||||
}
|
||||
|
||||
if (PreviousAddress < Limit) {
|
||||
Status = ConvertMemoryPageAttributes (PageTable, mPagingMode, PreviousAddress, Limit - PreviousAddress, EFI_MEMORY_XP, TRUE, NULL);
|
||||
ASSERT_RETURN_ERROR (Status);
|
||||
}
|
||||
|
||||
//
|
||||
// Do not free mUefiMemoryMap, it will be checked in IsSmmCommBufferForbiddenAddress().
|
||||
// Set NonMmram to not-present by excluding "RT, Reserved and NVS" memory type when RestrictedMemoryAccess is enabled.
|
||||
//
|
||||
|
||||
//
|
||||
// Set untested memory as not present.
|
||||
//
|
||||
if (mGcdMemSpace != NULL) {
|
||||
for (Index = 0; Index < mGcdMemNumberOfDesc; Index++) {
|
||||
Status = SmmSetMemoryAttributes (
|
||||
mGcdMemSpace[Index].BaseAddress,
|
||||
mGcdMemSpace[Index].Length,
|
||||
EFI_MEMORY_RP
|
||||
);
|
||||
DEBUG ((
|
||||
DEBUG_INFO,
|
||||
"GcdMemory protection: 0x%lx - 0x%lx %r\n",
|
||||
mGcdMemSpace[Index].BaseAddress,
|
||||
mGcdMemSpace[Index].BaseAddress + mGcdMemSpace[Index].Length,
|
||||
Status
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Do not free mGcdMemSpace, it will be checked in IsSmmCommBufferForbiddenAddress().
|
||||
//
|
||||
|
||||
//
|
||||
// Set UEFI runtime memory with EFI_MEMORY_RO as not present.
|
||||
//
|
||||
if (mUefiMemoryAttributesTable != NULL) {
|
||||
Entry = (EFI_MEMORY_DESCRIPTOR *)(mUefiMemoryAttributesTable + 1);
|
||||
for (Index = 0; Index < mUefiMemoryAttributesTable->NumberOfEntries; Index++) {
|
||||
if ((Entry->Type == EfiRuntimeServicesCode) || (Entry->Type == EfiRuntimeServicesData)) {
|
||||
if ((Entry->Attribute & EFI_MEMORY_RO) != 0) {
|
||||
Status = SmmSetMemoryAttributes (
|
||||
Entry->PhysicalStart,
|
||||
EFI_PAGES_TO_SIZE ((UINTN)Entry->NumberOfPages),
|
||||
EFI_MEMORY_RP
|
||||
if (IsRestrictedMemoryAccess ()) {
|
||||
if (mUefiMemoryMap != NULL) {
|
||||
MemoryMapEntryCount = mUefiMemoryMapSize/mUefiDescriptorSize;
|
||||
MemoryMap = mUefiMemoryMap;
|
||||
for (Index = 0; Index < MemoryMapEntryCount; Index++) {
|
||||
if (IsUefiPageNotPresent (MemoryMap)) {
|
||||
Status = ConvertMemoryPageAttributes (
|
||||
PageTable,
|
||||
mPagingMode,
|
||||
MemoryMap->PhysicalStart,
|
||||
EFI_PAGES_TO_SIZE ((UINTN)MemoryMap->NumberOfPages),
|
||||
EFI_MEMORY_RP,
|
||||
TRUE,
|
||||
NULL
|
||||
);
|
||||
DEBUG ((
|
||||
DEBUG_INFO,
|
||||
"UefiMemoryAttribute protection: 0x%lx - 0x%lx %r\n",
|
||||
Entry->PhysicalStart,
|
||||
Entry->PhysicalStart + (UINT64)EFI_PAGES_TO_SIZE ((UINTN)Entry->NumberOfPages),
|
||||
"UefiMemory protection: 0x%lx - 0x%lx %r\n",
|
||||
MemoryMap->PhysicalStart,
|
||||
MemoryMap->PhysicalStart + (UINT64)EFI_PAGES_TO_SIZE ((UINTN)MemoryMap->NumberOfPages),
|
||||
Status
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
Entry = NEXT_MEMORY_DESCRIPTOR (Entry, mUefiMemoryAttributesTable->DescriptorSize);
|
||||
MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, mUefiDescriptorSize);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Do not free mUefiMemoryMap, it will be checked in IsSmmCommBufferForbiddenAddress().
|
||||
//
|
||||
|
||||
//
|
||||
// Set untested NonMmram memory as not present.
|
||||
//
|
||||
if (mGcdMemSpace != NULL) {
|
||||
for (Index = 0; Index < mGcdMemNumberOfDesc; Index++) {
|
||||
Status = ConvertMemoryPageAttributes (
|
||||
PageTable,
|
||||
mPagingMode,
|
||||
mGcdMemSpace[Index].BaseAddress,
|
||||
mGcdMemSpace[Index].Length,
|
||||
EFI_MEMORY_RP,
|
||||
TRUE,
|
||||
NULL
|
||||
);
|
||||
DEBUG ((
|
||||
DEBUG_INFO,
|
||||
"GcdMemory protection: 0x%lx - 0x%lx %r\n",
|
||||
mGcdMemSpace[Index].BaseAddress,
|
||||
mGcdMemSpace[Index].BaseAddress + mGcdMemSpace[Index].Length,
|
||||
Status
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Do not free mGcdMemSpace, it will be checked in IsSmmCommBufferForbiddenAddress().
|
||||
//
|
||||
|
||||
//
|
||||
// Above logic sets the whole RT memory as present.
|
||||
// Below logic is to set the RT code as not present.
|
||||
//
|
||||
if (mUefiMemoryAttributesTable != NULL) {
|
||||
Entry = (EFI_MEMORY_DESCRIPTOR *)(mUefiMemoryAttributesTable + 1);
|
||||
for (Index = 0; Index < mUefiMemoryAttributesTable->NumberOfEntries; Index++) {
|
||||
if ((Entry->Type == EfiRuntimeServicesCode) || (Entry->Type == EfiRuntimeServicesData)) {
|
||||
if ((Entry->Attribute & EFI_MEMORY_RO) != 0) {
|
||||
Status = ConvertMemoryPageAttributes (
|
||||
PageTable,
|
||||
mPagingMode,
|
||||
Entry->PhysicalStart,
|
||||
EFI_PAGES_TO_SIZE ((UINTN)Entry->NumberOfPages),
|
||||
EFI_MEMORY_RP,
|
||||
TRUE,
|
||||
NULL
|
||||
);
|
||||
DEBUG ((
|
||||
DEBUG_INFO,
|
||||
"UefiMemoryAttribute protection: 0x%lx - 0x%lx %r\n",
|
||||
Entry->PhysicalStart,
|
||||
Entry->PhysicalStart + (UINT64)EFI_PAGES_TO_SIZE ((UINTN)Entry->NumberOfPages),
|
||||
Status
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
Entry = NEXT_MEMORY_DESCRIPTOR (Entry, mUefiMemoryAttributesTable->DescriptorSize);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Do not free mUefiMemoryAttributesTable, it will be checked in IsSmmCommBufferForbiddenAddress().
|
||||
//
|
||||
}
|
||||
|
||||
//
|
||||
// Flush TLB
|
||||
//
|
||||
CpuFlushTlb ();
|
||||
|
||||
//
|
||||
// Set execute-disable flag
|
||||
//
|
||||
mXdEnabled = TRUE;
|
||||
|
||||
WRITE_PROTECT_RO_PAGES (WriteProtect, CetEnabled);
|
||||
|
||||
//
|
||||
// Do not free mUefiMemoryAttributesTable, it will be checked in IsSmmCommBufferForbiddenAddress().
|
||||
//
|
||||
|
||||
PERF_FUNCTION_END ();
|
||||
DEBUG ((DEBUG_INFO, "UpdateUefiMemMapAttributes Done.\n"));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -958,14 +958,6 @@ SetMemMapAttributes (
|
||||
EDKII_PI_SMM_MEMORY_ATTRIBUTES_TABLE *MemoryAttributesTable
|
||||
);
|
||||
|
||||
/**
|
||||
This function sets UEFI memory attribute according to UEFI memory map.
|
||||
**/
|
||||
VOID
|
||||
SetUefiMemMapAttributes (
|
||||
VOID
|
||||
);
|
||||
|
||||
/**
|
||||
Get SmmProfileData.
|
||||
|
||||
@ -1037,6 +1029,15 @@ CreateNonMmramMemMap (
|
||||
OUT UINTN *MemoryRegionCount
|
||||
);
|
||||
|
||||
/**
|
||||
This function updates UEFI memory attribute according to UEFI memory map.
|
||||
|
||||
**/
|
||||
VOID
|
||||
UpdateUefiMemMapAttributes (
|
||||
VOID
|
||||
);
|
||||
|
||||
/**
|
||||
This function caches the UEFI memory map information.
|
||||
**/
|
||||
|
@ -58,9 +58,13 @@ PerformRemainingTasks (
|
||||
}
|
||||
|
||||
//
|
||||
// Create a mix of 2MB and 4KB page table. Update some memory ranges absent and execute-disable.
|
||||
// Update Page Table for outside SMRAM.
|
||||
//
|
||||
InitPaging ();
|
||||
if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {
|
||||
SmmProfileUpdateMemoryAttributes ();
|
||||
} else {
|
||||
UpdateUefiMemMapAttributes ();
|
||||
}
|
||||
|
||||
//
|
||||
// gEdkiiPiSmmMemoryAttributesTableGuid should have been published at EndOfDxe by SmmCore
|
||||
@ -77,11 +81,6 @@ PerformRemainingTasks (
|
||||
}
|
||||
|
||||
if (IsRestrictedMemoryAccess ()) {
|
||||
//
|
||||
// For outside SMRAM, we only map SMM communication buffer or MMIO.
|
||||
//
|
||||
SetUefiMemMapAttributes ();
|
||||
|
||||
//
|
||||
// Set page table itself to be read-only
|
||||
//
|
||||
|
@ -573,11 +573,11 @@ InitProtectedMemRange (
|
||||
}
|
||||
|
||||
/**
|
||||
Update page table according to protected memory ranges and the 4KB-page mapped memory ranges.
|
||||
This function updates memory attribute according to mProtectionMemRangeCount.
|
||||
|
||||
**/
|
||||
VOID
|
||||
InitPaging (
|
||||
SmmProfileUpdateMemoryAttributes (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
@ -592,91 +592,67 @@ InitPaging (
|
||||
BOOLEAN WriteProtect;
|
||||
BOOLEAN CetEnabled;
|
||||
|
||||
PERF_FUNCTION_BEGIN ();
|
||||
DEBUG ((DEBUG_INFO, "SmmProfileUpdateMemoryAttributes Start...\n"));
|
||||
|
||||
WRITE_UNPROTECT_RO_PAGES (WriteProtect, CetEnabled);
|
||||
|
||||
PageTable = AsmReadCr3 ();
|
||||
Limit = LShiftU64 (1, mPhysicalAddressBits);
|
||||
|
||||
WRITE_UNPROTECT_RO_PAGES (WriteProtect, CetEnabled);
|
||||
|
||||
//
|
||||
// [0, 4k] may be non-present.
|
||||
//
|
||||
PreviousAddress = ((PcdGet8 (PcdNullPointerDetectionPropertyMask) & BIT1) != 0) ? BASE_4KB : 0;
|
||||
|
||||
DEBUG ((DEBUG_INFO, "Patch page table start ...\n"));
|
||||
if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {
|
||||
for (Index = 0; Index < mProtectionMemRangeCount; Index++) {
|
||||
MemoryAttrMask = 0;
|
||||
if (mProtectionMemRange[Index].Nx == TRUE) {
|
||||
MemoryAttrMask |= EFI_MEMORY_XP;
|
||||
}
|
||||
|
||||
if (mProtectionMemRange[Index].Present == FALSE) {
|
||||
MemoryAttrMask = EFI_MEMORY_RP;
|
||||
}
|
||||
|
||||
Base = mProtectionMemRange[Index].Range.Base;
|
||||
Length = mProtectionMemRange[Index].Range.Top - Base;
|
||||
if (MemoryAttrMask != 0) {
|
||||
Status = ConvertMemoryPageAttributes (PageTable, mPagingMode, Base, Length, MemoryAttrMask, TRUE, NULL);
|
||||
ASSERT_RETURN_ERROR (Status);
|
||||
}
|
||||
|
||||
if (Base > PreviousAddress) {
|
||||
//
|
||||
// Mark the ranges not in mProtectionMemRange as non-present.
|
||||
//
|
||||
MemoryAttrMask = EFI_MEMORY_RP;
|
||||
Status = ConvertMemoryPageAttributes (PageTable, mPagingMode, PreviousAddress, Base - PreviousAddress, MemoryAttrMask, TRUE, NULL);
|
||||
ASSERT_RETURN_ERROR (Status);
|
||||
}
|
||||
|
||||
PreviousAddress = Base + Length;
|
||||
for (Index = 0; Index < mProtectionMemRangeCount; Index++) {
|
||||
MemoryAttrMask = 0;
|
||||
if (mProtectionMemRange[Index].Nx == TRUE) {
|
||||
MemoryAttrMask = EFI_MEMORY_XP;
|
||||
}
|
||||
|
||||
//
|
||||
// This assignment is for setting the last remaining range
|
||||
//
|
||||
MemoryAttrMask = EFI_MEMORY_RP;
|
||||
} else {
|
||||
MemoryAttrMask = EFI_MEMORY_XP;
|
||||
for (Index = 0; Index < mSmmCpuSmramRangeCount; Index++) {
|
||||
Base = mSmmCpuSmramRanges[Index].CpuStart;
|
||||
if (Base > PreviousAddress) {
|
||||
//
|
||||
// Mark the ranges not in mSmmCpuSmramRanges as NX.
|
||||
//
|
||||
Status = ConvertMemoryPageAttributes (PageTable, mPagingMode, PreviousAddress, Base - PreviousAddress, MemoryAttrMask, TRUE, NULL);
|
||||
ASSERT_RETURN_ERROR (Status);
|
||||
}
|
||||
|
||||
PreviousAddress = mSmmCpuSmramRanges[Index].CpuStart + mSmmCpuSmramRanges[Index].PhysicalSize;
|
||||
if (mProtectionMemRange[Index].Present == FALSE) {
|
||||
MemoryAttrMask = EFI_MEMORY_RP;
|
||||
}
|
||||
|
||||
Base = mProtectionMemRange[Index].Range.Base;
|
||||
Length = mProtectionMemRange[Index].Range.Top - Base;
|
||||
if (MemoryAttrMask != 0) {
|
||||
Status = ConvertMemoryPageAttributes (PageTable, mPagingMode, Base, Length, MemoryAttrMask, TRUE, NULL);
|
||||
ASSERT_RETURN_ERROR (Status);
|
||||
}
|
||||
|
||||
if (Base > PreviousAddress) {
|
||||
//
|
||||
// Mark the ranges not in mProtectionMemRange as non-present.
|
||||
//
|
||||
Status = ConvertMemoryPageAttributes (PageTable, mPagingMode, PreviousAddress, Base - PreviousAddress, EFI_MEMORY_RP, TRUE, NULL);
|
||||
ASSERT_RETURN_ERROR (Status);
|
||||
}
|
||||
|
||||
PreviousAddress = Base + Length;
|
||||
}
|
||||
|
||||
//
|
||||
// Set the last remaining range
|
||||
//
|
||||
if (PreviousAddress < Limit) {
|
||||
//
|
||||
// Set the last remaining range to EFI_MEMORY_RP/EFI_MEMORY_XP.
|
||||
// This path applies to both SmmProfile enable/disable case.
|
||||
//
|
||||
Status = ConvertMemoryPageAttributes (PageTable, mPagingMode, PreviousAddress, Limit - PreviousAddress, MemoryAttrMask, TRUE, NULL);
|
||||
Status = ConvertMemoryPageAttributes (PageTable, mPagingMode, PreviousAddress, Limit - PreviousAddress, EFI_MEMORY_RP, TRUE, NULL);
|
||||
ASSERT_RETURN_ERROR (Status);
|
||||
}
|
||||
|
||||
WRITE_PROTECT_RO_PAGES (WriteProtect, CetEnabled);
|
||||
|
||||
//
|
||||
// Flush TLB
|
||||
//
|
||||
CpuFlushTlb ();
|
||||
DEBUG ((DEBUG_INFO, "Patch page table done!\n"));
|
||||
|
||||
//
|
||||
// Set execute-disable flag
|
||||
//
|
||||
mXdEnabled = TRUE;
|
||||
|
||||
PERF_FUNCTION_END ();
|
||||
WRITE_PROTECT_RO_PAGES (WriteProtect, CetEnabled);
|
||||
|
||||
DEBUG ((DEBUG_INFO, "SmmProfileUpdateMemoryAttributes Done.\n"));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -100,11 +100,11 @@ InitProtectedMemRange (
|
||||
);
|
||||
|
||||
/**
|
||||
Update page table according to protected memory ranges and the 4KB-page mapped memory ranges.
|
||||
This function updates memory attribute according to mProtectionMemRangeCount.
|
||||
|
||||
**/
|
||||
VOID
|
||||
InitPaging (
|
||||
SmmProfileUpdateMemoryAttributes (
|
||||
VOID
|
||||
);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user