/** @file\r
Enable SMM profile.\r
\r
-Copyright (c) 2012 - 2016, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2012 - 2019, Intel Corporation. All rights reserved.<BR>\r
Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>\r
\r
-This program and the accompanying materials\r
-are licensed and made available under the terms and conditions of the BSD License\r
-which accompanies this distribution. The full text of the license may be found at\r
-http://opensource.org/licenses/bsd-license.php\r
-\r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
\r
//\r
UINTN mMsrDsAreaSize = SMM_PROFILE_DTS_SIZE;\r
\r
+//\r
+// The flag indicates if execute-disable is supported by processor.\r
+//\r
+BOOLEAN mXdSupported = TRUE;\r
+\r
//\r
// The flag indicates if execute-disable is enabled on processor.\r
//\r
//\r
BOOLEAN mSmmProfileStart = FALSE;\r
\r
+//\r
+// The flag indicates if #DB will be setup in #PF handler.\r
+//\r
+BOOLEAN mSetupDebugTrap = FALSE;\r
+\r
//\r
// Record the page fault exception count for one instruction execution.\r
//\r
//\r
{{0x00000000, 0x00000000},TRUE,TRUE},\r
\r
+ //\r
+ // SMRAM ranges not covered by mCpuHotPlugData.SmrrBase/mCpuHotPlugData.SmrrSiz (to be fixed in runtime).\r
+ // It is always present and instruction fetches are allowed.\r
+ // {{0x00000000, 0x00000000},TRUE,FALSE},\r
+ //\r
+\r
//\r
// Future extended range could be added here.\r
//\r
UINTN CpuIndex;\r
UINTN PFEntry;\r
\r
- if (!mSmmProfileStart) {\r
+ if (!mSmmProfileStart &&\r
+ !HEAP_GUARD_NONSTOP_MODE &&\r
+ !NULL_DETECTION_NONSTOP_MODE) {\r
return;\r
}\r
CpuIndex = GetCpuIndex ();\r
ClearTrapFlag (SystemContext);\r
}\r
\r
+/**\r
+ Check if the input address is in SMM ranges.\r
+\r
+ @param[in] Address The input address.\r
+\r
+ @retval TRUE The input address is in SMM.\r
+ @retval FALSE The input address is not in SMM.\r
+**/\r
+BOOLEAN\r
+IsInSmmRanges (\r
+ IN EFI_PHYSICAL_ADDRESS Address\r
+ )\r
+{\r
+ UINTN Index;\r
+\r
+ if ((Address >= mCpuHotPlugData.SmrrBase) && (Address < mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize)) {\r
+ return TRUE;\r
+ }\r
+ for (Index = 0; Index < mSmmCpuSmramRangeCount; Index++) {\r
+ if (Address >= mSmmCpuSmramRanges[Index].CpuStart &&\r
+ Address < mSmmCpuSmramRanges[Index].CpuStart + mSmmCpuSmramRanges[Index].PhysicalSize) {\r
+ return TRUE;\r
+ }\r
+ }\r
+ return FALSE;\r
+}\r
+\r
/**\r
Check if the memory address will be mapped by 4KB-page.\r
\r
{\r
UINTN Index;\r
\r
- *Nx = FALSE;\r
if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {\r
//\r
// Check configuration\r
return FALSE;\r
\r
} else {\r
- if ((Address < mCpuHotPlugData.SmrrBase) ||\r
- (Address >= mCpuHotPlugData.SmrrBase + mCpuHotPlugData.SmrrSize)) {\r
- *Nx = TRUE;\r
+ *Nx = TRUE;\r
+ if (IsInSmmRanges (Address)) {\r
+ *Nx = FALSE;\r
}\r
return TRUE;\r
}\r
{\r
UINTN Index;\r
UINTN NumberOfDescriptors;\r
- UINTN NumberOfMmioDescriptors;\r
+ UINTN NumberOfAddedDescriptors;\r
UINTN NumberOfProtectRange;\r
UINTN NumberOfSpliteRange;\r
EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;\r
UINT64 Low4KBPageSize;\r
\r
NumberOfDescriptors = 0;\r
- NumberOfMmioDescriptors = 0;\r
+ NumberOfAddedDescriptors = mSmmCpuSmramRangeCount;\r
NumberOfSpliteRange = 0;\r
MemorySpaceMap = NULL;\r
\r
);\r
for (Index = 0; Index < NumberOfDescriptors; Index++) {\r
if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) {\r
- NumberOfMmioDescriptors++;\r
+ NumberOfAddedDescriptors++;\r
}\r
}\r
\r
- if (NumberOfMmioDescriptors != 0) {\r
- TotalSize = NumberOfMmioDescriptors * sizeof (MEMORY_PROTECTION_RANGE) + sizeof (mProtectionMemRangeTemplate);\r
+ if (NumberOfAddedDescriptors != 0) {\r
+ TotalSize = NumberOfAddedDescriptors * sizeof (MEMORY_PROTECTION_RANGE) + sizeof (mProtectionMemRangeTemplate);\r
mProtectionMemRange = (MEMORY_PROTECTION_RANGE *) AllocateZeroPool (TotalSize);\r
ASSERT (mProtectionMemRange != NULL);\r
mProtectionMemRangeCount = TotalSize / sizeof (MEMORY_PROTECTION_RANGE);\r
mSplitMemRange = (MEMORY_RANGE *) AllocateZeroPool (TotalSize);\r
ASSERT (mSplitMemRange != NULL);\r
\r
+ //\r
+ // Create SMM ranges which are set to present and execution-enable.\r
+ //\r
+ NumberOfProtectRange = sizeof (mProtectionMemRangeTemplate) / sizeof (MEMORY_PROTECTION_RANGE);\r
+ for (Index = 0; Index < mSmmCpuSmramRangeCount; Index++) {\r
+ if (mSmmCpuSmramRanges[Index].CpuStart >= mProtectionMemRange[0].Range.Base &&\r
+ mSmmCpuSmramRanges[Index].CpuStart + mSmmCpuSmramRanges[Index].PhysicalSize < mProtectionMemRange[0].Range.Top) {\r
+ //\r
+ // If the address have been already covered by mCpuHotPlugData.SmrrBase/mCpuHotPlugData.SmrrSiz\r
+ //\r
+ break;\r
+ }\r
+ mProtectionMemRange[NumberOfProtectRange].Range.Base = mSmmCpuSmramRanges[Index].CpuStart;\r
+ mProtectionMemRange[NumberOfProtectRange].Range.Top = mSmmCpuSmramRanges[Index].CpuStart + mSmmCpuSmramRanges[Index].PhysicalSize;\r
+ mProtectionMemRange[NumberOfProtectRange].Present = TRUE;\r
+ mProtectionMemRange[NumberOfProtectRange].Nx = FALSE;\r
+ NumberOfProtectRange++;\r
+ }\r
+\r
//\r
// Create MMIO ranges which are set to present and execution-disable.\r
//\r
- NumberOfProtectRange = sizeof (mProtectionMemRangeTemplate) / sizeof (MEMORY_PROTECTION_RANGE);\r
for (Index = 0; Index < NumberOfDescriptors; Index++) {\r
if (MemorySpaceMap[Index].GcdMemoryType != EfiGcdMemoryTypeMemoryMappedIo) {\r
continue;\r
mProtectionMemRange[NumberOfProtectRange].Nx = TRUE;\r
NumberOfProtectRange++;\r
}\r
+\r
+ //\r
+ // Check and updated actual protected memory ranges count\r
+ //\r
+ ASSERT (NumberOfProtectRange <= mProtectionMemRangeCount);\r
+ mProtectionMemRangeCount = NumberOfProtectRange;\r
}\r
\r
//\r
return ;\r
}\r
\r
-/**\r
- To find FADT in ACPI tables.\r
-\r
- @param AcpiTableGuid The GUID used to find ACPI table in UEFI ConfigurationTable.\r
-\r
- @return FADT table pointer.\r
-**/\r
-EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *\r
-FindAcpiFadtTableByAcpiGuid (\r
- IN EFI_GUID *AcpiTableGuid\r
- )\r
-{\r
- EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp;\r
- EFI_ACPI_DESCRIPTION_HEADER *Rsdt;\r
- EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *Fadt;\r
- UINTN Index;\r
- UINT32 Data32;\r
- Rsdp = NULL;\r
- Rsdt = NULL;\r
- Fadt = NULL;\r
- //\r
- // found ACPI table RSD_PTR from system table\r
- //\r
- for (Index = 0; Index < gST->NumberOfTableEntries; Index++) {\r
- if (CompareGuid (&(gST->ConfigurationTable[Index].VendorGuid), AcpiTableGuid)) {\r
- //\r
- // A match was found.\r
- //\r
- Rsdp = gST->ConfigurationTable[Index].VendorTable;\r
- break;\r
- }\r
- }\r
-\r
- if (Rsdp == NULL) {\r
- return NULL;\r
- }\r
-\r
- Rsdt = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN) Rsdp->RsdtAddress;\r
- if (Rsdt == NULL || Rsdt->Signature != EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_TABLE_SIGNATURE) {\r
- return NULL;\r
- }\r
-\r
- for (Index = sizeof (EFI_ACPI_DESCRIPTION_HEADER); Index < Rsdt->Length; Index = Index + sizeof (UINT32)) {\r
-\r
- Data32 = *(UINT32 *) ((UINT8 *) Rsdt + Index);\r
- Fadt = (EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *) (UINT32 *) (UINTN) Data32;\r
- if (Fadt->Header.Signature == EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE) {\r
- break;\r
- }\r
- }\r
-\r
- if (Fadt == NULL || Fadt->Header.Signature != EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE) {\r
- return NULL;\r
- }\r
-\r
- return Fadt;\r
-}\r
-\r
-/**\r
- To find FADT in ACPI tables.\r
-\r
- @return FADT table pointer.\r
-**/\r
-EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *\r
-FindAcpiFadtTable (\r
- VOID\r
- )\r
-{\r
- EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *Fadt;\r
-\r
- Fadt = FindAcpiFadtTableByAcpiGuid (&gEfiAcpi20TableGuid);\r
- if (Fadt != NULL) {\r
- return Fadt;\r
- }\r
-\r
- return FindAcpiFadtTableByAcpiGuid (&gEfiAcpi10TableGuid);\r
-}\r
-\r
/**\r
To get system port address of the SMI Command Port in FADT table.\r
\r
{\r
EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *Fadt;\r
\r
- Fadt = FindAcpiFadtTable ();\r
+ Fadt = (EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *) EfiLocateFirstAcpiTable (\r
+ EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE\r
+ );\r
ASSERT (Fadt != NULL);\r
\r
mSmiCommandPort = Fadt->SmiCmd;\r
}\r
\r
/**\r
- Check if XD feature is supported by a processor.\r
+ Check if feature is supported by a processor.\r
\r
**/\r
VOID\r
)\r
{\r
UINT32 RegEax;\r
+ UINT32 RegEcx;\r
UINT32 RegEdx;\r
MSR_IA32_MISC_ENABLE_REGISTER MiscEnableMsr;\r
\r
+ if ((PcdGet32 (PcdControlFlowEnforcementPropertyMask) != 0) && mCetSupported) {\r
+ AsmCpuid (CPUID_EXTENDED_FUNCTION, &RegEax, NULL, NULL, NULL);\r
+ if (RegEax <= CPUID_EXTENDED_FUNCTION) {\r
+ mCetSupported = FALSE;\r
+ PatchInstructionX86 (mPatchCetSupported, mCetSupported, 1);\r
+ }\r
+ AsmCpuidEx (CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS, CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS_SUB_LEAF_INFO, NULL, NULL, &RegEcx, NULL);\r
+ if ((RegEcx & CPUID_CET_SS) == 0) {\r
+ mCetSupported = FALSE;\r
+ PatchInstructionX86 (mPatchCetSupported, mCetSupported, 1);\r
+ }\r
+ }\r
+\r
if (mXdSupported) {\r
AsmCpuid (CPUID_EXTENDED_FUNCTION, &RegEax, NULL, NULL, NULL);\r
if (RegEax <= CPUID_EXTENDED_FUNCTION) {\r
// Extended CPUID functions are not supported on this processor.\r
//\r
mXdSupported = FALSE;\r
+ PatchInstructionX86 (gPatchXdSupported, mXdSupported, 1);\r
}\r
\r
AsmCpuid (CPUID_EXTENDED_CPU_SIG, NULL, NULL, NULL, &RegEdx);\r
// Execute Disable Bit feature is not supported on this processor.\r
//\r
mXdSupported = FALSE;\r
+ PatchInstructionX86 (gPatchXdSupported, mXdSupported, 1);\r
}\r
}\r
\r
//\r
// Skip SMM profile initialization if feature is disabled\r
//\r
- if (!FeaturePcdGet (PcdCpuSmmProfileEnable)) {\r
+ if (!FeaturePcdGet (PcdCpuSmmProfileEnable) &&\r
+ !HEAP_GUARD_NONSTOP_MODE &&\r
+ !NULL_DETECTION_NONSTOP_MODE) {\r
return;\r
}\r
\r
// Initialize profile IDT.\r
//\r
InitIdtr ();\r
+\r
+ //\r
+ // Tell #PF handler to prepare a #DB subsequently.\r
+ //\r
+ mSetupDebugTrap = TRUE;\r
}\r
\r
/**\r
}\r
}\r
\r
+/**\r
+ Handler for Page Fault triggered by Guard page.\r
+\r
+ @param ErrorCode The Error code of exception.\r
+\r
+**/\r
+VOID\r
+GuardPagePFHandler (\r
+ UINTN ErrorCode\r
+ )\r
+{\r
+ UINT64 *PageTable;\r
+ UINT64 PFAddress;\r
+ UINT64 RestoreAddress;\r
+ UINTN RestorePageNumber;\r
+ UINTN CpuIndex;\r
+\r
+ PageTable = (UINT64 *)AsmReadCr3 ();\r
+ PFAddress = AsmReadCr2 ();\r
+ CpuIndex = GetCpuIndex ();\r
+\r
+ //\r
+ // Memory operation cross pages, like "rep mov" instruction, will cause\r
+ // infinite loop between this and Debug Trap handler. We have to make sure\r
+ // that current page and the page followed are both in PRESENT state.\r
+ //\r
+ RestorePageNumber = 2;\r
+ RestoreAddress = PFAddress;\r
+ while (RestorePageNumber > 0) {\r
+ RestorePageTableBelow4G (PageTable, RestoreAddress, CpuIndex, ErrorCode);\r
+ RestoreAddress += EFI_PAGE_SIZE;\r
+ RestorePageNumber--;\r
+ }\r
+\r
+ //\r
+ // Flush TLB\r
+ //\r
+ CpuFlushTlb ();\r
+}\r
+\r
/**\r
The Page fault handler to save SMM profile data.\r
\r
{\r
UINT64 *PageTable;\r
UINT64 PFAddress;\r
+ UINT64 RestoreAddress;\r
+ UINTN RestorePageNumber;\r
UINTN CpuIndex;\r
UINTN Index;\r
UINT64 InstructionAddress;\r
PFAddress = AsmReadCr2 ();\r
CpuIndex = GetCpuIndex ();\r
\r
- if (PFAddress <= 0xFFFFFFFF) {\r
- RestorePageTableBelow4G (PageTable, PFAddress, CpuIndex, ErrorCode);\r
- } else {\r
- RestorePageTableAbove4G (PageTable, PFAddress, CpuIndex, ErrorCode, &IsValidPFAddress);\r
+ //\r
+ // Memory operation cross pages, like "rep mov" instruction, will cause\r
+ // infinite loop between this and Debug Trap handler. We have to make sure\r
+ // that current page and the page followed are both in PRESENT state.\r
+ //\r
+ RestorePageNumber = 2;\r
+ RestoreAddress = PFAddress;\r
+ while (RestorePageNumber > 0) {\r
+ if (RestoreAddress <= 0xFFFFFFFF) {\r
+ RestorePageTableBelow4G (PageTable, RestoreAddress, CpuIndex, ErrorCode);\r
+ } else {\r
+ RestorePageTableAbove4G (PageTable, RestoreAddress, CpuIndex, ErrorCode, &IsValidPFAddress);\r
+ }\r
+ RestoreAddress += EFI_PAGE_SIZE;\r
+ RestorePageNumber--;\r
}\r
\r
if (!IsValidPFAddress) {\r