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; 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 // Set own Page Fault entry instead of the default one, because SMM Profile
// feature depends on IRET instruction to do Single Step // feature depends on IRET instruction to do Single Step
@ -129,6 +131,11 @@ SmiPFHandler (
DumpModuleInfoByIp ((UINTN)SystemContext.SystemContextIa32->Eip); DumpModuleInfoByIp ((UINTN)SystemContext.SystemContextIa32->Eip);
); );
} }
if (HEAP_GUARD_NONSTOP_MODE) {
GuardPagePFHandler (SystemContext.SystemContextIa32->ExceptionData);
goto Exit;
}
} }
CpuDeadLoop (); CpuDeadLoop ();
} }
@ -146,6 +153,26 @@ SmiPFHandler (
); );
CpuDeadLoop (); 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)) { if (IsSmmCommBufferForbiddenAddress (PFAddress)) {
DumpCpuContext (InterruptType, SystemContext); DumpCpuContext (InterruptType, SystemContext);
DEBUG ((DEBUG_ERROR, "Access SMM communication forbidden address (0x%x)!\n", PFAddress)); 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)) { if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {
SmmProfilePFHandler ( SmmProfilePFHandler (
SystemContext.SystemContextIa32->Eip, SystemContext.SystemContextIa32->Eip,
@ -179,6 +193,7 @@ SmiPFHandler (
SmiDefaultPFHandler (); SmiDefaultPFHandler ();
} }
Exit:
ReleaseSpinLock (mPFLock); ReleaseSpinLock (mPFLock);
} }

View File

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

View File

@ -51,6 +51,11 @@ BOOLEAN mBtsSupported = TRUE;
// //
BOOLEAN mSmmProfileStart = FALSE; 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. // Record the page fault exception count for one instruction execution.
// //
@ -229,7 +234,9 @@ DebugExceptionHandler (
UINTN CpuIndex; UINTN CpuIndex;
UINTN PFEntry; UINTN PFEntry;
if (!mSmmProfileStart) { if (!mSmmProfileStart &&
!HEAP_GUARD_NONSTOP_MODE &&
!NULL_DETECTION_NONSTOP_MODE) {
return; return;
} }
CpuIndex = GetCpuIndex (); CpuIndex = GetCpuIndex ();
@ -1174,7 +1181,9 @@ InitSmmProfile (
// //
// Skip SMM profile initialization if feature is disabled // Skip SMM profile initialization if feature is disabled
// //
if (!FeaturePcdGet (PcdCpuSmmProfileEnable)) { if (!FeaturePcdGet (PcdCpuSmmProfileEnable) &&
!HEAP_GUARD_NONSTOP_MODE &&
!NULL_DETECTION_NONSTOP_MODE) {
return; return;
} }
@ -1187,6 +1196,11 @@ InitSmmProfile (
// Initialize profile IDT. // Initialize profile IDT.
// //
InitIdtr (); 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. The Page fault handler to save SMM profile data.

View File

@ -114,6 +114,17 @@ GetCpuIndex (
VOID 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. // 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. // The flag indicates if execute-disable is enabled on processor.
// //
extern BOOLEAN mXdEnabled; extern BOOLEAN mXdEnabled;
//
// The flag indicates if #DB will be setup in #PF handler.
//
extern BOOLEAN mSetupDebugTrap;
#endif // _SMM_PROFILE_H_ #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_DEBUG_CTL_BTINT 0x100
#define MSR_DS_AREA 0x600 #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 { typedef struct {
EFI_PHYSICAL_ADDRESS Base; EFI_PHYSICAL_ADDRESS Base;
EFI_PHYSICAL_ADDRESS Top; 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 // Set own Page Fault entry instead of the default one, because SMM Profile
// feature depends on IRET instruction to do Single Step // feature depends on IRET instruction to do Single Step
@ -846,6 +848,11 @@ SmiPFHandler (
DumpModuleInfoByIp ((UINTN)SystemContext.SystemContextX64->Rip); DumpModuleInfoByIp ((UINTN)SystemContext.SystemContextX64->Rip);
); );
} }
if (HEAP_GUARD_NONSTOP_MODE) {
GuardPagePFHandler (SystemContext.SystemContextX64->ExceptionData);
goto Exit;
}
} }
CpuDeadLoop (); CpuDeadLoop ();
} }
@ -863,6 +870,26 @@ SmiPFHandler (
); );
CpuDeadLoop (); 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)) { if (IsSmmCommBufferForbiddenAddress (PFAddress)) {
DumpCpuContext (InterruptType, SystemContext); DumpCpuContext (InterruptType, SystemContext);
DEBUG ((DEBUG_ERROR, "Access SMM communication forbidden address (0x%lx)!\n", PFAddress)); 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)) { if (FeaturePcdGet (PcdCpuSmmProfileEnable)) {
SmmProfilePFHandler ( SmmProfilePFHandler (
SystemContext.SystemContextX64->Rip, SystemContext.SystemContextX64->Rip,
@ -895,6 +909,7 @@ SmiPFHandler (
SmiDefaultPFHandler (); SmiDefaultPFHandler ();
} }
Exit:
ReleaseSpinLock (mPFLock); ReleaseSpinLock (mPFLock);
} }