mirror of https://github.com/acidanthera/audk.git
UefiCpuPkg/CpuDxe: implement non-stop mode for uefi
Same as SMM profile feature, a special #PF is used to set page attribute to 'present' and a special #DB handler to reset it back to 'not-present', right after the instruction causing #PF got executed. Since the new #PF handler won't enter into dead-loop, the instruction which caused the #PF will get chance to re-execute with accessible pages. The exception message will still be printed out on debug console so that the developer/QA can find that there's potential heap overflow or null pointer access occurred. 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:
parent
16b918bbaf
commit
dcc026217f
|
@ -57,6 +57,12 @@
|
||||||
EFI_MEMORY_RO \
|
EFI_MEMORY_RO \
|
||||||
)
|
)
|
||||||
|
|
||||||
|
#define HEAP_GUARD_NONSTOP_MODE \
|
||||||
|
((PcdGet8 (PcdHeapGuardPropertyMask) & (BIT6|BIT1|BIT0)) > BIT6)
|
||||||
|
|
||||||
|
#define NULL_DETECTION_NONSTOP_MODE \
|
||||||
|
((PcdGet8 (PcdNullPointerDetectionPropertyMask) & (BIT6|BIT0)) > BIT6)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Flush CPU data cache. If the instruction cache is fully coherent
|
Flush CPU data cache. If the instruction cache is fully coherent
|
||||||
with all DMA operations then function can just return EFI_SUCCESS.
|
with all DMA operations then function can just return EFI_SUCCESS.
|
||||||
|
@ -273,7 +279,40 @@ RefreshGcdMemoryAttributesFromPaging (
|
||||||
VOID
|
VOID
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Special handler for #DB exception, which will restore the page attributes
|
||||||
|
(not-present). It should work with #PF handler which will set pages to
|
||||||
|
'present'.
|
||||||
|
|
||||||
|
@param ExceptionType Exception type.
|
||||||
|
@param SystemContext Pointer to EFI_SYSTEM_CONTEXT.
|
||||||
|
|
||||||
|
**/
|
||||||
|
VOID
|
||||||
|
EFIAPI
|
||||||
|
DebugExceptionHandler (
|
||||||
|
IN EFI_EXCEPTION_TYPE InterruptType,
|
||||||
|
IN EFI_SYSTEM_CONTEXT SystemContext
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Special handler for #PF exception, which will set the pages which caused
|
||||||
|
#PF to be 'present'. The attribute of those pages should be restored in
|
||||||
|
the subsequent #DB handler.
|
||||||
|
|
||||||
|
@param ExceptionType Exception type.
|
||||||
|
@param SystemContext Pointer to EFI_SYSTEM_CONTEXT.
|
||||||
|
|
||||||
|
**/
|
||||||
|
VOID
|
||||||
|
EFIAPI
|
||||||
|
PageFaultExceptionHandler (
|
||||||
|
IN EFI_EXCEPTION_TYPE InterruptType,
|
||||||
|
IN EFI_SYSTEM_CONTEXT SystemContext
|
||||||
|
);
|
||||||
|
|
||||||
extern BOOLEAN mIsAllocatingPageTable;
|
extern BOOLEAN mIsAllocatingPageTable;
|
||||||
|
extern UINTN mNumberOfProcessors;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,7 @@
|
||||||
ReportStatusCodeLib
|
ReportStatusCodeLib
|
||||||
MpInitLib
|
MpInitLib
|
||||||
TimerLib
|
TimerLib
|
||||||
|
PeCoffGetEntryPointLib
|
||||||
|
|
||||||
[Sources]
|
[Sources]
|
||||||
CpuDxe.c
|
CpuDxe.c
|
||||||
|
@ -79,6 +80,8 @@
|
||||||
[Pcd]
|
[Pcd]
|
||||||
gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask ## CONSUMES
|
gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask ## CONSUMES
|
||||||
gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard ## CONSUMES
|
gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard ## CONSUMES
|
||||||
|
gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPropertyMask ## CONSUMES
|
||||||
|
gEfiMdeModulePkgTokenSpaceGuid.PcdNullPointerDetectionPropertyMask ## CONSUMES
|
||||||
gUefiCpuPkgTokenSpaceGuid.PcdCpuStackSwitchExceptionList ## CONSUMES
|
gUefiCpuPkgTokenSpaceGuid.PcdCpuStackSwitchExceptionList ## CONSUMES
|
||||||
gUefiCpuPkgTokenSpaceGuid.PcdCpuKnownGoodStackSize ## CONSUMES
|
gUefiCpuPkgTokenSpaceGuid.PcdCpuKnownGoodStackSize ## CONSUMES
|
||||||
|
|
||||||
|
|
|
@ -673,10 +673,6 @@ InitializeMpExceptionStackSwitchHandlers (
|
||||||
UINT8 *GdtBuffer;
|
UINT8 *GdtBuffer;
|
||||||
UINT8 *StackTop;
|
UINT8 *StackTop;
|
||||||
|
|
||||||
if (!PcdGetBool (PcdCpuStackGuard)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ExceptionNumber = FixedPcdGetSize (PcdCpuStackSwitchExceptionList);
|
ExceptionNumber = FixedPcdGetSize (PcdCpuStackSwitchExceptionList);
|
||||||
NewStackSize = FixedPcdGet32 (PcdCpuKnownGoodStackSize) * ExceptionNumber;
|
NewStackSize = FixedPcdGet32 (PcdCpuKnownGoodStackSize) * ExceptionNumber;
|
||||||
|
|
||||||
|
@ -790,6 +786,32 @@ InitializeMpExceptionStackSwitchHandlers (
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Initializes MP exceptions handlers for special features, such as Heap Guard
|
||||||
|
and Stack Guard.
|
||||||
|
**/
|
||||||
|
VOID
|
||||||
|
InitializeMpExceptionHandlers (
|
||||||
|
VOID
|
||||||
|
)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// Enable non-stop mode for #PF triggered by Heap Guard or NULL Pointer
|
||||||
|
// Detection.
|
||||||
|
//
|
||||||
|
if (HEAP_GUARD_NONSTOP_MODE || NULL_DETECTION_NONSTOP_MODE) {
|
||||||
|
RegisterCpuInterruptHandler (EXCEPT_IA32_DEBUG, DebugExceptionHandler);
|
||||||
|
RegisterCpuInterruptHandler (EXCEPT_IA32_PAGE_FAULT, PageFaultExceptionHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Setup stack switch for Stack Guard feature.
|
||||||
|
//
|
||||||
|
if (PcdGetBool (PcdCpuStackGuard)) {
|
||||||
|
InitializeMpExceptionStackSwitchHandlers ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Initialize Multi-processor support.
|
Initialize Multi-processor support.
|
||||||
|
|
||||||
|
@ -814,9 +836,9 @@ InitializeMpSupport (
|
||||||
DEBUG ((DEBUG_INFO, "Detect CPU count: %d\n", mNumberOfProcessors));
|
DEBUG ((DEBUG_INFO, "Detect CPU count: %d\n", mNumberOfProcessors));
|
||||||
|
|
||||||
//
|
//
|
||||||
// Initialize exception stack switch handlers for each logic processor.
|
// Initialize special exception handlers for each logic processor.
|
||||||
//
|
//
|
||||||
InitializeMpExceptionStackSwitchHandlers ();
|
InitializeMpExceptionHandlers ();
|
||||||
|
|
||||||
//
|
//
|
||||||
// Update CPU healthy information from Guided HOB
|
// Update CPU healthy information from Guided HOB
|
||||||
|
|
|
@ -22,6 +22,10 @@
|
||||||
#include <Library/MemoryAllocationLib.h>
|
#include <Library/MemoryAllocationLib.h>
|
||||||
#include <Library/DebugLib.h>
|
#include <Library/DebugLib.h>
|
||||||
#include <Library/UefiBootServicesTableLib.h>
|
#include <Library/UefiBootServicesTableLib.h>
|
||||||
|
#include <Library/PeCoffGetEntryPointLib.h>
|
||||||
|
#include <Library/SerialPortLib.h>
|
||||||
|
#include <Library/SynchronizationLib.h>
|
||||||
|
#include <Library/PrintLib.h>
|
||||||
#include <Protocol/MpService.h>
|
#include <Protocol/MpService.h>
|
||||||
#include <Protocol/SmmBase2.h>
|
#include <Protocol/SmmBase2.h>
|
||||||
#include <Register/Cpuid.h>
|
#include <Register/Cpuid.h>
|
||||||
|
@ -73,6 +77,10 @@
|
||||||
#define PAGING_2M_ADDRESS_MASK_64 0x000FFFFFFFE00000ull
|
#define PAGING_2M_ADDRESS_MASK_64 0x000FFFFFFFE00000ull
|
||||||
#define PAGING_1G_ADDRESS_MASK_64 0x000FFFFFC0000000ull
|
#define PAGING_1G_ADDRESS_MASK_64 0x000FFFFFC0000000ull
|
||||||
|
|
||||||
|
#define MAX_PF_ENTRY_COUNT 10
|
||||||
|
#define MAX_DEBUG_MESSAGE_LENGTH 0x100
|
||||||
|
#define IA32_PF_EC_ID BIT4
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
PageNone,
|
PageNone,
|
||||||
Page4K,
|
Page4K,
|
||||||
|
@ -102,6 +110,12 @@ PAGE_TABLE_POOL *mPageTablePool = NULL;
|
||||||
PAGE_TABLE_LIB_PAGING_CONTEXT mPagingContext;
|
PAGE_TABLE_LIB_PAGING_CONTEXT mPagingContext;
|
||||||
EFI_SMM_BASE2_PROTOCOL *mSmmBase2 = NULL;
|
EFI_SMM_BASE2_PROTOCOL *mSmmBase2 = NULL;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Record the page fault exception count for one instruction execution.
|
||||||
|
//
|
||||||
|
UINTN *mPFEntryCount;
|
||||||
|
UINT64 *(*mLastPFEntryPointer)[MAX_PF_ENTRY_COUNT];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Check if current execution environment is in SMM mode or not, via
|
Check if current execution environment is in SMM mode or not, via
|
||||||
EFI_SMM_BASE2_PROTOCOL.
|
EFI_SMM_BASE2_PROTOCOL.
|
||||||
|
@ -1135,6 +1149,150 @@ AllocatePageTableMemory (
|
||||||
return Buffer;
|
return Buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Special handler for #DB exception, which will restore the page attributes
|
||||||
|
(not-present). It should work with #PF handler which will set pages to
|
||||||
|
'present'.
|
||||||
|
|
||||||
|
@param ExceptionType Exception type.
|
||||||
|
@param SystemContext Pointer to EFI_SYSTEM_CONTEXT.
|
||||||
|
|
||||||
|
**/
|
||||||
|
VOID
|
||||||
|
EFIAPI
|
||||||
|
DebugExceptionHandler (
|
||||||
|
IN EFI_EXCEPTION_TYPE ExceptionType,
|
||||||
|
IN EFI_SYSTEM_CONTEXT SystemContext
|
||||||
|
)
|
||||||
|
{
|
||||||
|
UINTN CpuIndex;
|
||||||
|
UINTN PFEntry;
|
||||||
|
BOOLEAN IsWpEnabled;
|
||||||
|
|
||||||
|
MpInitLibWhoAmI (&CpuIndex);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Clear last PF entries
|
||||||
|
//
|
||||||
|
IsWpEnabled = IsReadOnlyPageWriteProtected ();
|
||||||
|
if (IsWpEnabled) {
|
||||||
|
DisableReadOnlyPageWriteProtect ();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (PFEntry = 0; PFEntry < mPFEntryCount[CpuIndex]; PFEntry++) {
|
||||||
|
if (mLastPFEntryPointer[CpuIndex][PFEntry] != NULL) {
|
||||||
|
*mLastPFEntryPointer[CpuIndex][PFEntry] &= ~IA32_PG_P;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsWpEnabled) {
|
||||||
|
EnableReadOnlyPageWriteProtect ();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Reset page fault exception count for next page fault.
|
||||||
|
//
|
||||||
|
mPFEntryCount[CpuIndex] = 0;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Flush TLB
|
||||||
|
//
|
||||||
|
CpuFlushTlb ();
|
||||||
|
|
||||||
|
//
|
||||||
|
// Clear TF in EFLAGS
|
||||||
|
//
|
||||||
|
if (mPagingContext.MachineType == IMAGE_FILE_MACHINE_I386) {
|
||||||
|
SystemContext.SystemContextIa32->Eflags &= (UINT32)~BIT8;
|
||||||
|
} else {
|
||||||
|
SystemContext.SystemContextX64->Rflags &= (UINT64)~BIT8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Special handler for #PF exception, which will set the pages which caused
|
||||||
|
#PF to be 'present'. The attribute of those pages should be restored in
|
||||||
|
the subsequent #DB handler.
|
||||||
|
|
||||||
|
@param ExceptionType Exception type.
|
||||||
|
@param SystemContext Pointer to EFI_SYSTEM_CONTEXT.
|
||||||
|
|
||||||
|
**/
|
||||||
|
VOID
|
||||||
|
EFIAPI
|
||||||
|
PageFaultExceptionHandler (
|
||||||
|
IN EFI_EXCEPTION_TYPE ExceptionType,
|
||||||
|
IN EFI_SYSTEM_CONTEXT SystemContext
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EFI_STATUS Status;
|
||||||
|
UINT64 PFAddress;
|
||||||
|
PAGE_TABLE_LIB_PAGING_CONTEXT PagingContext;
|
||||||
|
PAGE_ATTRIBUTE PageAttribute;
|
||||||
|
UINT64 Attributes;
|
||||||
|
UINT64 *PageEntry;
|
||||||
|
UINTN Index;
|
||||||
|
UINTN CpuIndex;
|
||||||
|
UINTN PageNumber;
|
||||||
|
BOOLEAN NonStopMode;
|
||||||
|
|
||||||
|
PFAddress = AsmReadCr2 () & ~EFI_PAGE_MASK;
|
||||||
|
if (PFAddress < BASE_4KB) {
|
||||||
|
NonStopMode = NULL_DETECTION_NONSTOP_MODE ? TRUE : FALSE;
|
||||||
|
} else {
|
||||||
|
NonStopMode = HEAP_GUARD_NONSTOP_MODE ? TRUE : FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NonStopMode) {
|
||||||
|
MpInitLibWhoAmI (&CpuIndex);
|
||||||
|
GetCurrentPagingContext (&PagingContext);
|
||||||
|
//
|
||||||
|
// Memory operation cross page boundary, 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.
|
||||||
|
//
|
||||||
|
PageNumber = 2;
|
||||||
|
while (PageNumber > 0) {
|
||||||
|
PageEntry = GetPageTableEntry (&PagingContext, PFAddress, &PageAttribute);
|
||||||
|
ASSERT(PageEntry != NULL);
|
||||||
|
|
||||||
|
if (PageEntry != NULL) {
|
||||||
|
Attributes = GetAttributesFromPageEntry (PageEntry);
|
||||||
|
if ((Attributes & EFI_MEMORY_RP) != 0) {
|
||||||
|
Attributes &= ~EFI_MEMORY_RP;
|
||||||
|
Status = AssignMemoryPageAttributes (&PagingContext, PFAddress,
|
||||||
|
EFI_PAGE_SIZE, Attributes, NULL);
|
||||||
|
if (!EFI_ERROR(Status)) {
|
||||||
|
Index = mPFEntryCount[CpuIndex];
|
||||||
|
//
|
||||||
|
// Re-retrieve page entry because above calling might update page
|
||||||
|
// table due to table split.
|
||||||
|
//
|
||||||
|
PageEntry = GetPageTableEntry (&PagingContext, PFAddress, &PageAttribute);
|
||||||
|
mLastPFEntryPointer[CpuIndex][Index++] = PageEntry;
|
||||||
|
mPFEntryCount[CpuIndex] = Index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PFAddress += EFI_PAGE_SIZE;
|
||||||
|
--PageNumber;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Initialize the serial port before dumping.
|
||||||
|
//
|
||||||
|
SerialPortInitialize ();
|
||||||
|
//
|
||||||
|
// Display ExceptionType, CPU information and Image information
|
||||||
|
//
|
||||||
|
DumpCpuContext (ExceptionType, SystemContext);
|
||||||
|
if (!NonStopMode) {
|
||||||
|
CpuDeadLoop ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Initialize the Page Table lib.
|
Initialize the Page Table lib.
|
||||||
**/
|
**/
|
||||||
|
@ -1158,6 +1316,15 @@ InitializePageTableLib (
|
||||||
EnableReadOnlyPageWriteProtect ();
|
EnableReadOnlyPageWriteProtect ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (HEAP_GUARD_NONSTOP_MODE || NULL_DETECTION_NONSTOP_MODE) {
|
||||||
|
mPFEntryCount = (UINTN *)AllocateZeroPool (sizeof (UINTN) * mNumberOfProcessors);
|
||||||
|
ASSERT (mPFEntryCount != NULL);
|
||||||
|
|
||||||
|
mLastPFEntryPointer = (UINT64 *(*)[MAX_PF_ENTRY_COUNT])
|
||||||
|
AllocateZeroPool (sizeof (mLastPFEntryPointer[0]) * mNumberOfProcessors);
|
||||||
|
ASSERT (mLastPFEntryPointer != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
DEBUG ((DEBUG_INFO, "CurrentPagingContext:\n", CurrentPagingContext.MachineType));
|
DEBUG ((DEBUG_INFO, "CurrentPagingContext:\n", CurrentPagingContext.MachineType));
|
||||||
DEBUG ((DEBUG_INFO, " MachineType - 0x%x\n", CurrentPagingContext.MachineType));
|
DEBUG ((DEBUG_INFO, " MachineType - 0x%x\n", CurrentPagingContext.MachineType));
|
||||||
DEBUG ((DEBUG_INFO, " PageTableBase - 0x%x\n", CurrentPagingContext.ContextData.X64.PageTableBase));
|
DEBUG ((DEBUG_INFO, " PageTableBase - 0x%x\n", CurrentPagingContext.ContextData.X64.PageTableBase));
|
||||||
|
|
Loading…
Reference in New Issue