UefiCpuPkg/PiSmmCpuDxeSmm: implement non-stop mode for SMM

Since SMM profile feature has already implemented non-stop mode if #PF
occurred, this patch just makes use of the existing implementation to
accommodate heap guard and NULL pointer detection feature.

Cc: Eric Dong <eric.dong@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>
Cc: Ruiyu Ni <ruiyu.ni@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Jian J Wang <jian.j.wang@intel.com>
Reviewed-by: Eric Dong <eric.dong@intel.com>
Acked-by: Laszlo Ersek <lersek@redhat.com>
This commit is contained in:
Jian J Wang 2018-08-20 11:35:58 +08:00
parent dcc026217f
commit 09afd9a42a
6 changed files with 137 additions and 31 deletions

View File

@ -38,7 +38,9 @@ SmmInitPageTable (
mPhysicalAddressBits = 32;
if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {
if (FeaturePcdGet (PcdCpuSmmProfileEnable) ||
HEAP_GUARD_NONSTOP_MODE ||
NULL_DETECTION_NONSTOP_MODE) {
//
// Set own Page Fault entry instead of the default one, because SMM Profile
// feature depends on IRET instruction to do Single Step
@ -129,6 +131,11 @@ SmiPFHandler (
DumpModuleInfoByIp ((UINTN)SystemContext.SystemContextIa32->Eip);
);
}
if (HEAP_GUARD_NONSTOP_MODE) {
GuardPagePFHandler (SystemContext.SystemContextIa32->ExceptionData);
goto Exit;
}
}
CpuDeadLoop ();
}
@ -146,6 +153,26 @@ SmiPFHandler (
);
CpuDeadLoop ();
}
//
// If NULL pointer was just accessed
//
if ((PcdGet8 (PcdNullPointerDetectionPropertyMask) & BIT1) != 0 &&
(PFAddress < EFI_PAGE_SIZE)) {
DumpCpuContext (InterruptType, SystemContext);
DEBUG ((DEBUG_ERROR, "!!! NULL pointer access !!!\n"));
DEBUG_CODE (
DumpModuleInfoByIp ((UINTN)SystemContext.SystemContextIa32->Eip);
);
if (NULL_DETECTION_NONSTOP_MODE) {
GuardPagePFHandler (SystemContext.SystemContextIa32->ExceptionData);
goto Exit;
}
CpuDeadLoop ();
}
if (IsSmmCommBufferForbiddenAddress (PFAddress)) {
DumpCpuContext (InterruptType, SystemContext);
DEBUG ((DEBUG_ERROR, "Access SMM communication forbidden address (0x%x)!\n", PFAddress));
@ -156,19 +183,6 @@ SmiPFHandler (
}
}
//
// If NULL pointer was just accessed
//
if ((PcdGet8 (PcdNullPointerDetectionPropertyMask) & BIT1) != 0 &&
(PFAddress < EFI_PAGE_SIZE)) {
DumpCpuContext (InterruptType, SystemContext);
DEBUG ((DEBUG_ERROR, "!!! NULL pointer access !!!\n"));
DEBUG_CODE (
DumpModuleInfoByIp ((UINTN)SystemContext.SystemContextIa32->Eip);
);
CpuDeadLoop ();
}
if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {
SmmProfilePFHandler (
SystemContext.SystemContextIa32->Eip,
@ -179,6 +193,7 @@ SmiPFHandler (
SmiDefaultPFHandler ();
}
Exit:
ReleaseSpinLock (mPFLock);
}

View File

@ -20,6 +20,7 @@
extern ASM_PFX(FeaturePcdGet (PcdCpuSmmProfileEnable))
extern ASM_PFX(SmiPFHandler)
extern ASM_PFX(mSetupDebugTrap)
global ASM_PFX(gcSmiIdtr)
global ASM_PFX(gcSmiGdtr)
@ -673,7 +674,7 @@ o16 mov [ecx + IA32_TSS._SS], ax
mov esp, ebp
; Set single step DB# if SMM profile is enabled and page fault exception happens
cmp byte [dword ASM_PFX(FeaturePcdGet (PcdCpuSmmProfileEnable))], 0
cmp byte [dword ASM_PFX(mSetupDebugTrap)], 0
jz @Done2
; Create return context for iretd in stub function

View File

@ -51,6 +51,11 @@ BOOLEAN mBtsSupported = TRUE;
//
BOOLEAN mSmmProfileStart = FALSE;
//
// The flag indicates if #DB will be setup in #PF handler.
//
BOOLEAN mSetupDebugTrap = FALSE;
//
// Record the page fault exception count for one instruction execution.
//
@ -229,7 +234,9 @@ DebugExceptionHandler (
UINTN CpuIndex;
UINTN PFEntry;
if (!mSmmProfileStart) {
if (!mSmmProfileStart &&
!HEAP_GUARD_NONSTOP_MODE &&
!NULL_DETECTION_NONSTOP_MODE) {
return;
}
CpuIndex = GetCpuIndex ();
@ -1174,7 +1181,9 @@ InitSmmProfile (
//
// Skip SMM profile initialization if feature is disabled
//
if (!FeaturePcdGet (PcdCpuSmmProfileEnable)) {
if (!FeaturePcdGet (PcdCpuSmmProfileEnable) &&
!HEAP_GUARD_NONSTOP_MODE &&
!NULL_DETECTION_NONSTOP_MODE) {
return;
}
@ -1187,6 +1196,11 @@ InitSmmProfile (
// Initialize profile IDT.
//
InitIdtr ();
//
// Tell #PF handler to prepare a #DB subsequently.
//
mSetupDebugTrap = TRUE;
}
/**
@ -1294,6 +1308,46 @@ RestorePageTableBelow4G (
}
}
/**
Handler for Page Fault triggered by Guard page.
@param ErrorCode The Error code of exception.
**/
VOID
GuardPagePFHandler (
UINTN ErrorCode
)
{
UINT64 *PageTable;
UINT64 PFAddress;
UINT64 RestoreAddress;
UINTN RestorePageNumber;
UINTN CpuIndex;
PageTable = (UINT64 *)AsmReadCr3 ();
PFAddress = AsmReadCr2 ();
CpuIndex = GetCpuIndex ();
//
// Memory operation cross pages, like "rep mov" instruction, will cause
// infinite loop between this and Debug Trap handler. We have to make sure
// that current page and the page followed are both in PRESENT state.
//
RestorePageNumber = 2;
RestoreAddress = PFAddress;
while (RestorePageNumber > 0) {
RestorePageTableBelow4G (PageTable, RestoreAddress, CpuIndex, ErrorCode);
RestoreAddress += EFI_PAGE_SIZE;
RestorePageNumber--;
}
//
// Flush TLB
//
CpuFlushTlb ();
}
/**
The Page fault handler to save SMM profile data.

View File

@ -114,6 +114,17 @@ GetCpuIndex (
VOID
);
/**
Handler for Page Fault triggered by Guard page.
@param ErrorCode The Error code of exception.
**/
VOID
GuardPagePFHandler (
UINTN ErrorCode
);
//
// The flag indicates if execute-disable is supported by processor.
//
@ -122,5 +133,9 @@ extern BOOLEAN mXdSupported;
// The flag indicates if execute-disable is enabled on processor.
//
extern BOOLEAN mXdEnabled;
//
// The flag indicates if #DB will be setup in #PF handler.
//
extern BOOLEAN mSetupDebugTrap;
#endif // _SMM_PROFILE_H_

View File

@ -64,6 +64,12 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#define MSR_DEBUG_CTL_BTINT 0x100
#define MSR_DS_AREA 0x600
#define HEAP_GUARD_NONSTOP_MODE \
((PcdGet8 (PcdHeapGuardPropertyMask) & (BIT6|BIT3|BIT2)) > BIT6)
#define NULL_DETECTION_NONSTOP_MODE \
((PcdGet8 (PcdNullPointerDetectionPropertyMask) & (BIT6|BIT1)) > BIT6)
typedef struct {
EFI_PHYSICAL_ADDRESS Base;
EFI_PHYSICAL_ADDRESS Top;

View File

@ -300,7 +300,9 @@ SmmInitPageTable (
}
}
if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {
if (FeaturePcdGet (PcdCpuSmmProfileEnable) ||
HEAP_GUARD_NONSTOP_MODE ||
NULL_DETECTION_NONSTOP_MODE) {
//
// Set own Page Fault entry instead of the default one, because SMM Profile
// feature depends on IRET instruction to do Single Step
@ -846,6 +848,11 @@ SmiPFHandler (
DumpModuleInfoByIp ((UINTN)SystemContext.SystemContextX64->Rip);
);
}
if (HEAP_GUARD_NONSTOP_MODE) {
GuardPagePFHandler (SystemContext.SystemContextX64->ExceptionData);
goto Exit;
}
}
CpuDeadLoop ();
}
@ -863,6 +870,26 @@ SmiPFHandler (
);
CpuDeadLoop ();
}
//
// If NULL pointer was just accessed
//
if ((PcdGet8 (PcdNullPointerDetectionPropertyMask) & BIT1) != 0 &&
(PFAddress < EFI_PAGE_SIZE)) {
DumpCpuContext (InterruptType, SystemContext);
DEBUG ((DEBUG_ERROR, "!!! NULL pointer access !!!\n"));
DEBUG_CODE (
DumpModuleInfoByIp ((UINTN)SystemContext.SystemContextX64->Rip);
);
if (NULL_DETECTION_NONSTOP_MODE) {
GuardPagePFHandler (SystemContext.SystemContextX64->ExceptionData);
goto Exit;
}
CpuDeadLoop ();
}
if (IsSmmCommBufferForbiddenAddress (PFAddress)) {
DumpCpuContext (InterruptType, SystemContext);
DEBUG ((DEBUG_ERROR, "Access SMM communication forbidden address (0x%lx)!\n", PFAddress));
@ -873,19 +900,6 @@ SmiPFHandler (
}
}
//
// If NULL pointer was just accessed
//
if ((PcdGet8 (PcdNullPointerDetectionPropertyMask) & BIT1) != 0 &&
(PFAddress < EFI_PAGE_SIZE)) {
DumpCpuContext (InterruptType, SystemContext);
DEBUG ((DEBUG_ERROR, "!!! NULL pointer access !!!\n"));
DEBUG_CODE (
DumpModuleInfoByIp ((UINTN)SystemContext.SystemContextX64->Rip);
);
CpuDeadLoop ();
}
if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {
SmmProfilePFHandler (
SystemContext.SystemContextX64->Rip,
@ -895,6 +909,7 @@ SmiPFHandler (
SmiDefaultPFHandler ();
}
Exit:
ReleaseSpinLock (mPFLock);
}