* [PATCH v2 0/4] Support non-stop mode in heap guard and null detection
@ 2018-08-21 3:05 Jian J Wang
2018-08-21 3:05 ` [PATCH v2 1/4] MdeModulePkg/MdeModulePkg.dec: add new settings for PCDs Jian J Wang
` (4 more replies)
0 siblings, 5 replies; 15+ messages in thread
From: Jian J Wang @ 2018-08-21 3:05 UTC (permalink / raw)
To: edk2-devel
> v2 changes:
> fix GCC build error
Background:
Heap Guard and NULL Pointer Detection are very useful features to detect
code flaw in EDK II. If an issue is detected, #PF exception will be
triggered and the BIOS will enter into dead loop, which is the default
behavior of exception handling. From QA perspective, this default behavior
will block them to collect all tests result in reasonable time.
Solution:
This patch series update CpuDxe, PiSmmCpuDxeSmm and CpuExceptionHandlerLib
to allow the code to continue execution after #PF. The mechanism behind it
is the same as SMM Profile feature, in which a special #PF handler is
registered to set the page causing #PF to be 'present' and setup single
steop trap, then return the control back to the instruction accessing that
page. Once the instruction is re-executed, a #DB is triggered and a special
handler for it will be called to reset the page back to 'not-present'.
Usage:
The non-stop mode is enabled/disabled by BIT6 of following PCDs
gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPropertyMask
gEfiMdeModulePkgTokenSpaceGuid.PcdNullPointerDetectionPropertyMask
The default setting is 'disable'.
BZ Tracker:
https://bugzilla.tianocore.org/show_bug.cgi?id=1095
OS Boot Validation:
Platform: OVMF
OS (x64): Fedora 26, Ubuntu 18.04, Windows 10, Windows 7
Jian J Wang (4):
MdeModulePkg/MdeModulePkg.dec: add new settings for PCDs
UefiCpuPkg/CpuExceptionHandlerLib: Setup single step in #PF handler
UefiCpuPkg/CpuDxe: implement non-stop mode for uefi
UefiCpuPkg/PiSmmCpuDxeSmm: implement non-stop mode for SMM
MdeModulePkg/MdeModulePkg.dec | 4 +-
UefiCpuPkg/CpuDxe/CpuDxe.h | 39 +++
UefiCpuPkg/CpuDxe/CpuDxe.inf | 3 +
UefiCpuPkg/CpuDxe/CpuMp.c | 34 ++-
UefiCpuPkg/CpuDxe/CpuPageTable.c | 271 +++++++++++++++++++++
.../Ia32/ExceptionHandlerAsm.nasm | 7 +
.../Ia32/ExceptionTssEntryAsm.nasm | 4 +-
.../X64/ExceptionHandlerAsm.nasm | 4 +
UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/PageTbl.c | 43 ++--
UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.nasm | 3 +-
UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfile.c | 58 ++++-
UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfile.h | 15 ++
UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfileInternal.h | 6 +
UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c | 43 ++--
14 files changed, 493 insertions(+), 41 deletions(-)
--
2.16.2.windows.1
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v2 1/4] MdeModulePkg/MdeModulePkg.dec: add new settings for PCDs
2018-08-21 3:05 [PATCH v2 0/4] Support non-stop mode in heap guard and null detection Jian J Wang
@ 2018-08-21 3:05 ` Jian J Wang
2018-08-21 3:05 ` [PATCH v2 2/4] UefiCpuPkg/CpuExceptionHandlerLib: Setup single step in #PF handler Jian J Wang
` (3 subsequent siblings)
4 siblings, 0 replies; 15+ messages in thread
From: Jian J Wang @ 2018-08-21 3:05 UTC (permalink / raw)
To: edk2-devel; +Cc: Eric Dong, Laszlo Ersek, Ruiyu Ni
> v2 changes:
> n/a
BIT6 of PcdHeapGuardPropertyMask is used to enable/disable non-stop mode
of Heap Guard feature. It applies to both UEFI and SMM heap guard, if
any of them is enabled.
BIT6 of PcdNullPointerDetectionPropertyMask is used to enable/disable
non-stop mode of NULL Pointer Detection feature. It applies to both
UEFI and SMM NULL Pointer Detection, if any of them is enabled.
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>
---
MdeModulePkg/MdeModulePkg.dec | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec
index 6a6d9660ed..451115030c 100644
--- a/MdeModulePkg/MdeModulePkg.dec
+++ b/MdeModulePkg/MdeModulePkg.dec
@@ -932,7 +932,8 @@
# If enabled, accessing NULL address in UEFI or SMM code can be caught.<BR><BR>
# BIT0 - Enable NULL pointer detection for UEFI.<BR>
# BIT1 - Enable NULL pointer detection for SMM.<BR>
- # BIT2..6 - Reserved for future uses.<BR>
+ # BIT2..5 - Reserved for future uses.<BR>
+ # BIT6 - Enable non-stop mode.<BR>
# BIT7 - Disable NULL pointer detection just after EndOfDxe. <BR>
# This is a workaround for those unsolvable NULL access issues in
# OptionROM, boot loader, etc. It can also help to avoid unnecessary
@@ -1014,6 +1015,7 @@
# BIT1 - Enable UEFI pool guard.<BR>
# BIT2 - Enable SMM page guard.<BR>
# BIT3 - Enable SMM pool guard.<BR>
+ # BIT6 - Enable non-stop mode.<BR>
# BIT7 - The direction of Guard Page for Pool Guard.
# 0 - The returned pool is near the tail guard page.<BR>
# 1 - The returned pool is near the head guard page.<BR>
--
2.16.2.windows.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v2 2/4] UefiCpuPkg/CpuExceptionHandlerLib: Setup single step in #PF handler
2018-08-21 3:05 [PATCH v2 0/4] Support non-stop mode in heap guard and null detection Jian J Wang
2018-08-21 3:05 ` [PATCH v2 1/4] MdeModulePkg/MdeModulePkg.dec: add new settings for PCDs Jian J Wang
@ 2018-08-21 3:05 ` Jian J Wang
2018-08-21 14:39 ` Laszlo Ersek
2018-08-28 1:14 ` Dong, Eric
2018-08-21 3:05 ` [PATCH v2 3/4] UefiCpuPkg/CpuDxe: implement non-stop mode for uefi Jian J Wang
` (2 subsequent siblings)
4 siblings, 2 replies; 15+ messages in thread
From: Jian J Wang @ 2018-08-21 3:05 UTC (permalink / raw)
To: edk2-devel; +Cc: Eric Dong, Laszlo Ersek, Ruiyu Ni
> v2 changes:
> n/a
Once the #PF handler has set the page to be 'present', there should
be a way to reset it to 'not-present'. 'TF' bit in EFLAGS can be used
for this purpose. 'TF' bit will be set in interrupted function context
so that it can be triggered once the cpu control returns back to the
instruction causing #PF and re-execute it.
This is an necessary step to implement non-stop mode for 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>
---
.../Library/CpuExceptionHandlerLib/Ia32/ExceptionHandlerAsm.nasm | 7 +++++++
.../Library/CpuExceptionHandlerLib/Ia32/ExceptionTssEntryAsm.nasm | 4 +---
.../Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.nasm | 4 ++++
3 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionHandlerAsm.nasm b/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionHandlerAsm.nasm
index 45d6474091..6fcf5fb23f 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionHandlerAsm.nasm
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionHandlerAsm.nasm
@@ -383,6 +383,13 @@ ErrorCodeAndVectorOnStack:
pop dword [ebp - 4]
mov esp, ebp
pop ebp
+
+; Enable TF bit after page fault handler runs
+ cmp dword [esp], 14 ; #PF?
+ jne .5
+ bts dword [esp + 16], 8 ; EFLAGS
+
+.5:
add esp, 8
cmp dword [esp - 16], 0 ; check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
jz DoReturn
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionTssEntryAsm.nasm b/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionTssEntryAsm.nasm
index 62bcedea1a..7aac29c7e7 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionTssEntryAsm.nasm
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionTssEntryAsm.nasm
@@ -355,10 +355,8 @@ o16 mov [ecx + IA32_TSS._SS], ax
movzx ebx, word [ecx + IA32_TSS._CS]
mov [eax - 0x8], ebx ; create CS in old stack
mov ebx, dword [ecx + IA32_TSS.EFLAGS]
- bts ebx, 8
+ bts ebx, 8 ; Set TF
mov [eax - 0x4], ebx ; create eflags in old stack
- mov dword [ecx + IA32_TSS.EFLAGS], ebx ; update eflags in old TSS
- mov eax, dword [ecx + IA32_TSS._ESP] ; Get old stack pointer
sub eax, 0xc ; minus 12 byte
mov dword [ecx + IA32_TSS._ESP], eax ; Set new stack pointer
diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.nasm b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.nasm
index 7b97810d10..f842af2336 100644
--- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.nasm
+++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.nasm
@@ -336,6 +336,10 @@ HasErrorCode:
pop r15
mov rsp, rbp
+ cmp qword [rbp + 8], 14 ; #PF?
+ jne .1
+ bts qword [rsp + 40], 8 ; RFLAGS.TF
+.1:
pop rbp
add rsp, 16
cmp qword [rsp - 32], 0 ; check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
--
2.16.2.windows.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v2 3/4] UefiCpuPkg/CpuDxe: implement non-stop mode for uefi
2018-08-21 3:05 [PATCH v2 0/4] Support non-stop mode in heap guard and null detection Jian J Wang
2018-08-21 3:05 ` [PATCH v2 1/4] MdeModulePkg/MdeModulePkg.dec: add new settings for PCDs Jian J Wang
2018-08-21 3:05 ` [PATCH v2 2/4] UefiCpuPkg/CpuExceptionHandlerLib: Setup single step in #PF handler Jian J Wang
@ 2018-08-21 3:05 ` Jian J Wang
2018-08-21 14:58 ` Laszlo Ersek
2018-08-21 3:05 ` [PATCH v2 4/4] UefiCpuPkg/PiSmmCpuDxeSmm: implement non-stop mode for SMM Jian J Wang
2018-08-21 14:28 ` [PATCH v2 0/4] Support non-stop mode in heap guard and null detection Laszlo Ersek
4 siblings, 1 reply; 15+ messages in thread
From: Jian J Wang @ 2018-08-21 3:05 UTC (permalink / raw)
To: edk2-devel; +Cc: Eric Dong, Laszlo Ersek, Ruiyu Ni
> v2 changes:
> n/a
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>
---
UefiCpuPkg/CpuDxe/CpuDxe.h | 39 ++++++
UefiCpuPkg/CpuDxe/CpuDxe.inf | 3 +
UefiCpuPkg/CpuDxe/CpuMp.c | 34 ++++-
UefiCpuPkg/CpuDxe/CpuPageTable.c | 271 +++++++++++++++++++++++++++++++++++++++
4 files changed, 341 insertions(+), 6 deletions(-)
diff --git a/UefiCpuPkg/CpuDxe/CpuDxe.h b/UefiCpuPkg/CpuDxe/CpuDxe.h
index 540f5f2dbf..7d65e39e90 100644
--- a/UefiCpuPkg/CpuDxe/CpuDxe.h
+++ b/UefiCpuPkg/CpuDxe/CpuDxe.h
@@ -57,6 +57,12 @@
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
with all DMA operations then function can just return EFI_SUCCESS.
@@ -273,7 +279,40 @@ RefreshGcdMemoryAttributesFromPaging (
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 UINTN mNumberOfProcessors;
#endif
diff --git a/UefiCpuPkg/CpuDxe/CpuDxe.inf b/UefiCpuPkg/CpuDxe/CpuDxe.inf
index 6a199b72f7..97a381b046 100644
--- a/UefiCpuPkg/CpuDxe/CpuDxe.inf
+++ b/UefiCpuPkg/CpuDxe/CpuDxe.inf
@@ -46,6 +46,7 @@
ReportStatusCodeLib
MpInitLib
TimerLib
+ PeCoffGetEntryPointLib
[Sources]
CpuDxe.c
@@ -79,6 +80,8 @@
[Pcd]
gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask ## CONSUMES
gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPropertyMask ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdNullPointerDetectionPropertyMask ## CONSUMES
gUefiCpuPkgTokenSpaceGuid.PcdCpuStackSwitchExceptionList ## CONSUMES
gUefiCpuPkgTokenSpaceGuid.PcdCpuKnownGoodStackSize ## CONSUMES
diff --git a/UefiCpuPkg/CpuDxe/CpuMp.c b/UefiCpuPkg/CpuDxe/CpuMp.c
index 82145e7624..f8489eb1c3 100644
--- a/UefiCpuPkg/CpuDxe/CpuMp.c
+++ b/UefiCpuPkg/CpuDxe/CpuMp.c
@@ -673,10 +673,6 @@ InitializeMpExceptionStackSwitchHandlers (
UINT8 *GdtBuffer;
UINT8 *StackTop;
- if (!PcdGetBool (PcdCpuStackGuard)) {
- return;
- }
-
ExceptionNumber = FixedPcdGetSize (PcdCpuStackSwitchExceptionList);
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.
@@ -814,9 +836,9 @@ InitializeMpSupport (
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
diff --git a/UefiCpuPkg/CpuDxe/CpuPageTable.c b/UefiCpuPkg/CpuDxe/CpuPageTable.c
index df021798c0..b65f74bd72 100644
--- a/UefiCpuPkg/CpuDxe/CpuPageTable.c
+++ b/UefiCpuPkg/CpuDxe/CpuPageTable.c
@@ -22,6 +22,10 @@
#include <Library/MemoryAllocationLib.h>
#include <Library/DebugLib.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/SmmBase2.h>
#include <Register/Cpuid.h>
@@ -73,6 +77,10 @@
#define PAGING_2M_ADDRESS_MASK_64 0x000FFFFFFFE00000ull
#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 {
PageNone,
Page4K,
@@ -102,6 +110,13 @@ PAGE_TABLE_POOL *mPageTablePool = NULL;
PAGE_TABLE_LIB_PAGING_CONTEXT mPagingContext;
EFI_SMM_BASE2_PROTOCOL *mSmmBase2 = NULL;
+//
+// Record the page fault exception count for one instruction execution.
+//
+UINTN *mPFEntryCount;
+UINT64 (*mLastPFEntryValue)[MAX_PF_ENTRY_COUNT];
+UINT64 *(*mLastPFEntryPointer)[MAX_PF_ENTRY_COUNT];
+
/**
Check if current execution environment is in SMM mode or not, via
EFI_SMM_BASE2_PROTOCOL.
@@ -1135,6 +1150,253 @@ AllocatePageTableMemory (
return Buffer;
}
+/**
+ Prints a message to the serial port.
+
+ @param Format Format string for the message to print.
+ @param ... Variable argument list whose contents are accessed
+ based on the format string specified by Format.
+
+**/
+STATIC
+VOID
+EFIAPI
+InternalPrintMessage (
+ IN CONST CHAR8 *Format,
+ ...
+ )
+{
+ CHAR8 Buffer[MAX_DEBUG_MESSAGE_LENGTH];
+ VA_LIST Marker;
+
+ //
+ // Convert the message to an ASCII String
+ //
+ VA_START (Marker, Format);
+ AsciiVSPrint (Buffer, sizeof (Buffer), Format, Marker);
+ VA_END (Marker);
+
+ //
+ // Send the print string to a Serial Port
+ //
+ SerialPortWrite ((UINT8 *)Buffer, AsciiStrLen (Buffer));
+}
+
+/**
+ Find and display image base address and return image base and its entry point.
+
+ @param CurrentIp Current instruction pointer.
+
+**/
+STATIC
+VOID
+DumpModuleImageInfo (
+ IN UINTN CurrentIp
+ )
+{
+ EFI_STATUS Status;
+ UINTN Pe32Data;
+ VOID *PdbPointer;
+ VOID *EntryPoint;
+
+ Pe32Data = PeCoffSearchImageBase (CurrentIp);
+ if (Pe32Data == 0) {
+ InternalPrintMessage ("!!!! Can't find image information. !!!!\n");
+ } else {
+ //
+ // Find Image Base entry point
+ //
+ Status = PeCoffLoaderGetEntryPoint ((VOID *) Pe32Data, &EntryPoint);
+ if (EFI_ERROR (Status)) {
+ EntryPoint = NULL;
+ }
+ InternalPrintMessage ("!!!! Find image based on IP(0x%x) ", CurrentIp);
+ PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *) Pe32Data);
+ if (PdbPointer != NULL) {
+ InternalPrintMessage ("%a", PdbPointer);
+ } else {
+ InternalPrintMessage ("(No PDB) " );
+ }
+ InternalPrintMessage (
+ " (ImageBase=%016lp, EntryPoint=%016p) !!!!\n",
+ (VOID *) Pe32Data,
+ EntryPoint
+ );
+ }
+}
+
+/**
+ 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;
+ UINTN CurrentIp;
+ 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);
+ //
+ // Dump module image base and module entry point by RIP
+ //
+ if (mPagingContext.MachineType == IMAGE_FILE_MACHINE_I386) {
+ if ((SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_ID) != 0) {
+ //
+ // The EIP in SystemContext could not be used
+ // if it is page fault with I/D set.
+ //
+ CurrentIp = *(UINTN *)(UINTN)SystemContext.SystemContextIa32->Esp;
+ } else {
+ CurrentIp = (UINTN)SystemContext.SystemContextIa32->Eip;
+ }
+ } else {
+ if ((SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_ID) != 0) {
+ //
+ // The RIP in SystemContext could not be used
+ // if it is page fault with I/D set.
+ //
+ CurrentIp = *(UINTN *)(UINTN)SystemContext.SystemContextX64->Rsp;
+ } else {
+ CurrentIp = (UINTN)SystemContext.SystemContextX64->Rip;
+ }
+ }
+
+ DumpModuleImageInfo (CurrentIp);
+
+ if (!NonStopMode) {
+ CpuDeadLoop();
+ }
+}
+
/**
Initialize the Page Table lib.
**/
@@ -1158,6 +1420,15 @@ InitializePageTableLib (
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, " MachineType - 0x%x\n", CurrentPagingContext.MachineType));
DEBUG ((DEBUG_INFO, " PageTableBase - 0x%x\n", CurrentPagingContext.ContextData.X64.PageTableBase));
--
2.16.2.windows.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v2 4/4] UefiCpuPkg/PiSmmCpuDxeSmm: implement non-stop mode for SMM
2018-08-21 3:05 [PATCH v2 0/4] Support non-stop mode in heap guard and null detection Jian J Wang
` (2 preceding siblings ...)
2018-08-21 3:05 ` [PATCH v2 3/4] UefiCpuPkg/CpuDxe: implement non-stop mode for uefi Jian J Wang
@ 2018-08-21 3:05 ` Jian J Wang
2018-08-21 15:44 ` Laszlo Ersek
2018-08-21 14:28 ` [PATCH v2 0/4] Support non-stop mode in heap guard and null detection Laszlo Ersek
4 siblings, 1 reply; 15+ messages in thread
From: Jian J Wang @ 2018-08-21 3:05 UTC (permalink / raw)
To: edk2-devel; +Cc: Eric Dong, Laszlo Ersek, Ruiyu Ni
> v2 changes:
> fix GCC build error caused by an unused variable in GuardPagePFHandler()
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>
---
UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/PageTbl.c | 43 ++++++++++++------
UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.nasm | 3 +-
UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfile.c | 58 +++++++++++++++++++++++-
UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfile.h | 15 ++++++
UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfileInternal.h | 6 +++
UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c | 43 ++++++++++++------
6 files changed, 137 insertions(+), 31 deletions(-)
diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/PageTbl.c b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/PageTbl.c
index 9300a232e4..a32b736089 100644
--- a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/PageTbl.c
+++ b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/PageTbl.c
@@ -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);
}
diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.nasm b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.nasm
index fa02c1016c..879fa0ba63 100644
--- a/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.nasm
+++ b/UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.nasm
@@ -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
diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfile.c b/UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfile.c
index b4fe0bc23b..a743cf64f9 100644
--- a/UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfile.c
+++ b/UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfile.c
@@ -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.
diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfile.h b/UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfile.h
index 04a3dfb2e8..c2a48235ab 100644
--- a/UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfile.h
+++ b/UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfile.h
@@ -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_
diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfileInternal.h b/UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfileInternal.h
index 1613e9cd5c..bacb2f8ad3 100644
--- a/UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfileInternal.h
+++ b/UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfileInternal.h
@@ -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;
diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c
index 0fe944fc18..5bb7d57238 100644
--- a/UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c
+++ b/UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c
@@ -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);
}
--
2.16.2.windows.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH v2 0/4] Support non-stop mode in heap guard and null detection
2018-08-21 3:05 [PATCH v2 0/4] Support non-stop mode in heap guard and null detection Jian J Wang
` (3 preceding siblings ...)
2018-08-21 3:05 ` [PATCH v2 4/4] UefiCpuPkg/PiSmmCpuDxeSmm: implement non-stop mode for SMM Jian J Wang
@ 2018-08-21 14:28 ` Laszlo Ersek
2018-08-22 6:59 ` Wang, Jian J
4 siblings, 1 reply; 15+ messages in thread
From: Laszlo Ersek @ 2018-08-21 14:28 UTC (permalink / raw)
To: Jian J Wang, edk2-devel
On 08/21/18 05:05, Jian J Wang wrote:
>> v2 changes:
>> fix GCC build error
>
> Background:
> Heap Guard and NULL Pointer Detection are very useful features to detect
> code flaw in EDK II. If an issue is detected, #PF exception will be
> triggered and the BIOS will enter into dead loop, which is the default
> behavior of exception handling. From QA perspective, this default behavior
> will block them to collect all tests result in reasonable time.
>
> Solution:
> This patch series update CpuDxe, PiSmmCpuDxeSmm and CpuExceptionHandlerLib
> to allow the code to continue execution after #PF. The mechanism behind it
> is the same as SMM Profile feature, in which a special #PF handler is
> registered to set the page causing #PF to be 'present' and setup single
> steop trap, then return the control back to the instruction accessing that
> page. Once the instruction is re-executed, a #DB is triggered and a special
> handler for it will be called to reset the page back to 'not-present'.
>
> Usage:
> The non-stop mode is enabled/disabled by BIT6 of following PCDs
>
> gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPropertyMask
> gEfiMdeModulePkgTokenSpaceGuid.PcdNullPointerDetectionPropertyMask
>
> The default setting is 'disable'.
>
> BZ Tracker:
> https://bugzilla.tianocore.org/show_bug.cgi?id=1095
>
> OS Boot Validation:
> Platform: OVMF
> OS (x64): Fedora 26, Ubuntu 18.04, Windows 10, Windows 7
>
> Jian J Wang (4):
> MdeModulePkg/MdeModulePkg.dec: add new settings for PCDs
> UefiCpuPkg/CpuExceptionHandlerLib: Setup single step in #PF handler
> UefiCpuPkg/CpuDxe: implement non-stop mode for uefi
> UefiCpuPkg/PiSmmCpuDxeSmm: implement non-stop mode for SMM
>
> MdeModulePkg/MdeModulePkg.dec | 4 +-
> UefiCpuPkg/CpuDxe/CpuDxe.h | 39 +++
> UefiCpuPkg/CpuDxe/CpuDxe.inf | 3 +
> UefiCpuPkg/CpuDxe/CpuMp.c | 34 ++-
> UefiCpuPkg/CpuDxe/CpuPageTable.c | 271 +++++++++++++++++++++
> .../Ia32/ExceptionHandlerAsm.nasm | 7 +
> .../Ia32/ExceptionTssEntryAsm.nasm | 4 +-
> .../X64/ExceptionHandlerAsm.nasm | 4 +
> UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/PageTbl.c | 43 ++--
> UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.nasm | 3 +-
> UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfile.c | 58 ++++-
> UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfile.h | 15 ++
> UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfileInternal.h | 6 +
> UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c | 43 ++--
> 14 files changed, 493 insertions(+), 41 deletions(-)
>
(1) This looks like a feature addition, so please include the BZ
reference (1095) on the following wiki page:
https://github.com/tianocore/tianocore.github.io/wiki/EDK-II-Release-Planning
(under "Proposed Features")
(2) The general description should be moved (or copied) from this email
(v2 0/4) to patch #1 (v2 1/4). The cover letter is not captured in the
commit log, and I think there isn't going to be any other documentation
for the feature than the DEC file.
(Note that I'm not suggesting that you add the documentation to the DEC
file in patch #1 -- instead, the commit message on patch #1 should
contain it. Then people can find the commit from the DEC file with "git
blame", and read the description.)
Thanks
Laszlo
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2 2/4] UefiCpuPkg/CpuExceptionHandlerLib: Setup single step in #PF handler
2018-08-21 3:05 ` [PATCH v2 2/4] UefiCpuPkg/CpuExceptionHandlerLib: Setup single step in #PF handler Jian J Wang
@ 2018-08-21 14:39 ` Laszlo Ersek
2018-08-28 1:14 ` Dong, Eric
1 sibling, 0 replies; 15+ messages in thread
From: Laszlo Ersek @ 2018-08-21 14:39 UTC (permalink / raw)
To: Jian J Wang, edk2-devel; +Cc: Ruiyu Ni, Eric Dong
On 08/21/18 05:05, Jian J Wang wrote:
>> v2 changes:
>> n/a
>
> Once the #PF handler has set the page to be 'present', there should
> be a way to reset it to 'not-present'. 'TF' bit in EFLAGS can be used
> for this purpose. 'TF' bit will be set in interrupted function context
> so that it can be triggered once the cpu control returns back to the
> instruction causing #PF and re-execute it.
>
> This is an necessary step to implement non-stop mode for 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>
> ---
> .../Library/CpuExceptionHandlerLib/Ia32/ExceptionHandlerAsm.nasm | 7 +++++++
> .../Library/CpuExceptionHandlerLib/Ia32/ExceptionTssEntryAsm.nasm | 4 +---
> .../Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.nasm | 4 ++++
> 3 files changed, 12 insertions(+), 3 deletions(-)
>
> diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionHandlerAsm.nasm b/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionHandlerAsm.nasm
> index 45d6474091..6fcf5fb23f 100644
> --- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionHandlerAsm.nasm
> +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionHandlerAsm.nasm
> @@ -383,6 +383,13 @@ ErrorCodeAndVectorOnStack:
> pop dword [ebp - 4]
> mov esp, ebp
> pop ebp
> +
> +; Enable TF bit after page fault handler runs
> + cmp dword [esp], 14 ; #PF?
> + jne .5
> + bts dword [esp + 16], 8 ; EFLAGS
> +
> +.5:
> add esp, 8
> cmp dword [esp - 16], 0 ; check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
> jz DoReturn
> diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionTssEntryAsm.nasm b/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionTssEntryAsm.nasm
> index 62bcedea1a..7aac29c7e7 100644
> --- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionTssEntryAsm.nasm
> +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionTssEntryAsm.nasm
> @@ -355,10 +355,8 @@ o16 mov [ecx + IA32_TSS._SS], ax
> movzx ebx, word [ecx + IA32_TSS._CS]
> mov [eax - 0x8], ebx ; create CS in old stack
> mov ebx, dword [ecx + IA32_TSS.EFLAGS]
> - bts ebx, 8
> + bts ebx, 8 ; Set TF
> mov [eax - 0x4], ebx ; create eflags in old stack
> - mov dword [ecx + IA32_TSS.EFLAGS], ebx ; update eflags in old TSS
> - mov eax, dword [ecx + IA32_TSS._ESP] ; Get old stack pointer
> sub eax, 0xc ; minus 12 byte
> mov dword [ecx + IA32_TSS._ESP], eax ; Set new stack pointer
>
> diff --git a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.nasm b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.nasm
> index 7b97810d10..f842af2336 100644
> --- a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.nasm
> +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.nasm
> @@ -336,6 +336,10 @@ HasErrorCode:
> pop r15
>
> mov rsp, rbp
> + cmp qword [rbp + 8], 14 ; #PF?
> + jne .1
> + bts qword [rsp + 40], 8 ; RFLAGS.TF
> +.1:
> pop rbp
> add rsp, 16
> cmp qword [rsp - 32], 0 ; check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
>
I'll defer to Ray and Eric on this.
Thanks
Laszlo
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2 3/4] UefiCpuPkg/CpuDxe: implement non-stop mode for uefi
2018-08-21 3:05 ` [PATCH v2 3/4] UefiCpuPkg/CpuDxe: implement non-stop mode for uefi Jian J Wang
@ 2018-08-21 14:58 ` Laszlo Ersek
2018-08-22 7:13 ` Wang, Jian J
0 siblings, 1 reply; 15+ messages in thread
From: Laszlo Ersek @ 2018-08-21 14:58 UTC (permalink / raw)
To: Jian J Wang, edk2-devel; +Cc: Ruiyu Ni, Eric Dong
I only have some superficial comments here.
On 08/21/18 05:05, Jian J Wang wrote:
>> v2 changes:
>> n/a
>
> 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>
> ---
> UefiCpuPkg/CpuDxe/CpuDxe.h | 39 ++++++
> UefiCpuPkg/CpuDxe/CpuDxe.inf | 3 +
> UefiCpuPkg/CpuDxe/CpuMp.c | 34 ++++-
> UefiCpuPkg/CpuDxe/CpuPageTable.c | 271 +++++++++++++++++++++++++++++++++++++++
> 4 files changed, 341 insertions(+), 6 deletions(-)
>
> diff --git a/UefiCpuPkg/CpuDxe/CpuDxe.h b/UefiCpuPkg/CpuDxe/CpuDxe.h
> index 540f5f2dbf..7d65e39e90 100644
> --- a/UefiCpuPkg/CpuDxe/CpuDxe.h
> +++ b/UefiCpuPkg/CpuDxe/CpuDxe.h
> @@ -57,6 +57,12 @@
> 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
> with all DMA operations then function can just return EFI_SUCCESS.
> @@ -273,7 +279,40 @@ RefreshGcdMemoryAttributesFromPaging (
> 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 UINTN mNumberOfProcessors;
>
> #endif
>
> diff --git a/UefiCpuPkg/CpuDxe/CpuDxe.inf b/UefiCpuPkg/CpuDxe/CpuDxe.inf
> index 6a199b72f7..97a381b046 100644
> --- a/UefiCpuPkg/CpuDxe/CpuDxe.inf
> +++ b/UefiCpuPkg/CpuDxe/CpuDxe.inf
> @@ -46,6 +46,7 @@
> ReportStatusCodeLib
> MpInitLib
> TimerLib
> + PeCoffGetEntryPointLib
>
> [Sources]
> CpuDxe.c
> @@ -79,6 +80,8 @@
> [Pcd]
> gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask ## CONSUMES
> gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard ## CONSUMES
> + gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPropertyMask ## CONSUMES
> + gEfiMdeModulePkgTokenSpaceGuid.PcdNullPointerDetectionPropertyMask ## CONSUMES
> gUefiCpuPkgTokenSpaceGuid.PcdCpuStackSwitchExceptionList ## CONSUMES
> gUefiCpuPkgTokenSpaceGuid.PcdCpuKnownGoodStackSize ## CONSUMES
>
> diff --git a/UefiCpuPkg/CpuDxe/CpuMp.c b/UefiCpuPkg/CpuDxe/CpuMp.c
> index 82145e7624..f8489eb1c3 100644
> --- a/UefiCpuPkg/CpuDxe/CpuMp.c
> +++ b/UefiCpuPkg/CpuDxe/CpuMp.c
> @@ -673,10 +673,6 @@ InitializeMpExceptionStackSwitchHandlers (
> UINT8 *GdtBuffer;
> UINT8 *StackTop;
>
> - if (!PcdGetBool (PcdCpuStackGuard)) {
> - return;
> - }
> -
> ExceptionNumber = FixedPcdGetSize (PcdCpuStackSwitchExceptionList);
> 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.
>
> @@ -814,9 +836,9 @@ InitializeMpSupport (
> 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
The reworking of the InitializeMpExceptionStackSwitchHandlers() /
PcdGetBool (PcdCpuStackGuard) call sites look OK to me.
(1) However, some whitespace is missing before opening parentheses. See
eg. after "RegisterCpuInterruptHandler".
Please check the rest of the code for that as well.
> diff --git a/UefiCpuPkg/CpuDxe/CpuPageTable.c b/UefiCpuPkg/CpuDxe/CpuPageTable.c
> index df021798c0..b65f74bd72 100644
> --- a/UefiCpuPkg/CpuDxe/CpuPageTable.c
> +++ b/UefiCpuPkg/CpuDxe/CpuPageTable.c
> @@ -22,6 +22,10 @@
> #include <Library/MemoryAllocationLib.h>
> #include <Library/DebugLib.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/SmmBase2.h>
> #include <Register/Cpuid.h>
> @@ -73,6 +77,10 @@
> #define PAGING_2M_ADDRESS_MASK_64 0x000FFFFFFFE00000ull
> #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 {
> PageNone,
> Page4K,
> @@ -102,6 +110,13 @@ PAGE_TABLE_POOL *mPageTablePool = NULL;
> PAGE_TABLE_LIB_PAGING_CONTEXT mPagingContext;
> EFI_SMM_BASE2_PROTOCOL *mSmmBase2 = NULL;
>
> +//
> +// Record the page fault exception count for one instruction execution.
> +//
> +UINTN *mPFEntryCount;
> +UINT64 (*mLastPFEntryValue)[MAX_PF_ENTRY_COUNT];
(2) "mLastPFEntryValue" seems unused.
> +UINT64 *(*mLastPFEntryPointer)[MAX_PF_ENTRY_COUNT];
(3) I think mPFEntryCount and mLastPFEntryPointer could be made STATIC.
(Not sure if that's consistent with the rest of the variable definitions
though, in this file.)
> +
> /**
> Check if current execution environment is in SMM mode or not, via
> EFI_SMM_BASE2_PROTOCOL.
> @@ -1135,6 +1150,253 @@ AllocatePageTableMemory (
> return Buffer;
> }
>
> +/**
> + Prints a message to the serial port.
> +
> + @param Format Format string for the message to print.
> + @param ... Variable argument list whose contents are accessed
> + based on the format string specified by Format.
> +
> +**/
> +STATIC
> +VOID
> +EFIAPI
> +InternalPrintMessage (
> + IN CONST CHAR8 *Format,
> + ...
> + )
> +{
> + CHAR8 Buffer[MAX_DEBUG_MESSAGE_LENGTH];
> + VA_LIST Marker;
> +
> + //
> + // Convert the message to an ASCII String
> + //
> + VA_START (Marker, Format);
> + AsciiVSPrint (Buffer, sizeof (Buffer), Format, Marker);
> + VA_END (Marker);
> +
> + //
> + // Send the print string to a Serial Port
> + //
> + SerialPortWrite ((UINT8 *)Buffer, AsciiStrLen (Buffer));
> +}
> +
> +/**
> + Find and display image base address and return image base and its entry point.
> +
> + @param CurrentIp Current instruction pointer.
> +
> +**/
> +STATIC
> +VOID
> +DumpModuleImageInfo (
> + IN UINTN CurrentIp
> + )
> +{
> + EFI_STATUS Status;
> + UINTN Pe32Data;
> + VOID *PdbPointer;
> + VOID *EntryPoint;
> +
> + Pe32Data = PeCoffSearchImageBase (CurrentIp);
> + if (Pe32Data == 0) {
> + InternalPrintMessage ("!!!! Can't find image information. !!!!\n");
> + } else {
> + //
> + // Find Image Base entry point
> + //
> + Status = PeCoffLoaderGetEntryPoint ((VOID *) Pe32Data, &EntryPoint);
> + if (EFI_ERROR (Status)) {
> + EntryPoint = NULL;
> + }
> + InternalPrintMessage ("!!!! Find image based on IP(0x%x) ", CurrentIp);
> + PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *) Pe32Data);
> + if (PdbPointer != NULL) {
> + InternalPrintMessage ("%a", PdbPointer);
> + } else {
> + InternalPrintMessage ("(No PDB) " );
> + }
> + InternalPrintMessage (
> + " (ImageBase=%016lp, EntryPoint=%016p) !!!!\n",
> + (VOID *) Pe32Data,
> + EntryPoint
> + );
> + }
> +}
(4) Why is this function copied here? From a quick check, it looks
identical to DumpModuleImageInfo() in
"UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c".
And, DumpModuleImageInfo() is an extern function in
"UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h", and we
are (likely) already linking against that library instance. As a result
we'll have the same function twice in CpuDxe, once as STATIC, and
another time as extern.
If this is a useful utility function, then it should be elevated to a
public library API, and used from there. (I don't know where to add it,
I just find this code duplication regrettable.)
Thanks
Laszlo
> +
> +/**
> + 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;
> + UINTN CurrentIp;
> + 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);
> + //
> + // Dump module image base and module entry point by RIP
> + //
> + if (mPagingContext.MachineType == IMAGE_FILE_MACHINE_I386) {
> + if ((SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_ID) != 0) {
> + //
> + // The EIP in SystemContext could not be used
> + // if it is page fault with I/D set.
> + //
> + CurrentIp = *(UINTN *)(UINTN)SystemContext.SystemContextIa32->Esp;
> + } else {
> + CurrentIp = (UINTN)SystemContext.SystemContextIa32->Eip;
> + }
> + } else {
> + if ((SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_ID) != 0) {
> + //
> + // The RIP in SystemContext could not be used
> + // if it is page fault with I/D set.
> + //
> + CurrentIp = *(UINTN *)(UINTN)SystemContext.SystemContextX64->Rsp;
> + } else {
> + CurrentIp = (UINTN)SystemContext.SystemContextX64->Rip;
> + }
> + }
> +
> + DumpModuleImageInfo (CurrentIp);
> +
> + if (!NonStopMode) {
> + CpuDeadLoop();
> + }
> +}
> +
> /**
> Initialize the Page Table lib.
> **/
> @@ -1158,6 +1420,15 @@ InitializePageTableLib (
> 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, " MachineType - 0x%x\n", CurrentPagingContext.MachineType));
> DEBUG ((DEBUG_INFO, " PageTableBase - 0x%x\n", CurrentPagingContext.ContextData.X64.PageTableBase));
>
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2 4/4] UefiCpuPkg/PiSmmCpuDxeSmm: implement non-stop mode for SMM
2018-08-21 3:05 ` [PATCH v2 4/4] UefiCpuPkg/PiSmmCpuDxeSmm: implement non-stop mode for SMM Jian J Wang
@ 2018-08-21 15:44 ` Laszlo Ersek
2018-08-22 7:16 ` Wang, Jian J
0 siblings, 1 reply; 15+ messages in thread
From: Laszlo Ersek @ 2018-08-21 15:44 UTC (permalink / raw)
To: Jian J Wang, edk2-devel; +Cc: Ruiyu Ni, Eric Dong
On 08/21/18 05:05, Jian J Wang wrote:
>> v2 changes:
>> fix GCC build error caused by an unused variable in GuardPagePFHandler()
>
> 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>
> ---
> UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/PageTbl.c | 43 ++++++++++++------
> UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.nasm | 3 +-
> UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfile.c | 58 +++++++++++++++++++++++-
> UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfile.h | 15 ++++++
> UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfileInternal.h | 6 +++
> UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c | 43 ++++++++++++------
> 6 files changed, 137 insertions(+), 31 deletions(-)
It seems like the changes are no-ops for platforms that set all these
PCDs to zero, so from my side
Acked-by: Laszlo Ersek <lersek@redhat.com>
Thanks
Laszlo
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2 0/4] Support non-stop mode in heap guard and null detection
2018-08-21 14:28 ` [PATCH v2 0/4] Support non-stop mode in heap guard and null detection Laszlo Ersek
@ 2018-08-22 6:59 ` Wang, Jian J
0 siblings, 0 replies; 15+ messages in thread
From: Wang, Jian J @ 2018-08-22 6:59 UTC (permalink / raw)
To: Laszlo Ersek, edk2-devel@lists.01.org
Hi Laszlo,
Regards,
Jian
From: Laszlo Ersek [mailto:lersek@redhat.com]
Sent: Tuesday, August 21, 2018 10:28 PM
To: Wang, Jian J <jian.j.wang@intel.com>; edk2-devel@lists.01.org
Subject: Re: [edk2] [PATCH v2 0/4] Support non-stop mode in heap guard and null detection
On 08/21/18 05:05, Jian J Wang wrote:
>> v2 changes:
>> fix GCC build error
>
> Background:
> Heap Guard and NULL Pointer Detection are very useful features to detect
> code flaw in EDK II. If an issue is detected, #PF exception will be
> triggered and the BIOS will enter into dead loop, which is the default
> behavior of exception handling. From QA perspective, this default behavior
> will block them to collect all tests result in reasonable time.
>
> Solution:
> This patch series update CpuDxe, PiSmmCpuDxeSmm and CpuExceptionHandlerLib
> to allow the code to continue execution after #PF. The mechanism behind it
> is the same as SMM Profile feature, in which a special #PF handler is
> registered to set the page causing #PF to be 'present' and setup single
> steop trap, then return the control back to the instruction accessing that
> page. Once the instruction is re-executed, a #DB is triggered and a special
> handler for it will be called to reset the page back to 'not-present'.
>
> Usage:
> The non-stop mode is enabled/disabled by BIT6 of following PCDs
>
> gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPropertyMask
> gEfiMdeModulePkgTokenSpaceGuid.PcdNullPointerDetectionPropertyMask
>
> The default setting is 'disable'.
>
> BZ Tracker:
> https://bugzilla.tianocore.org/show_bug.cgi?id=1095
>
> OS Boot Validation:
> Platform: OVMF
> OS (x64): Fedora 26, Ubuntu 18.04, Windows 10, Windows 7
>
> Jian J Wang (4):
> MdeModulePkg/MdeModulePkg.dec: add new settings for PCDs
> UefiCpuPkg/CpuExceptionHandlerLib: Setup single step in #PF handler
> UefiCpuPkg/CpuDxe: implement non-stop mode for uefi
> UefiCpuPkg/PiSmmCpuDxeSmm: implement non-stop mode for SMM
>
> MdeModulePkg/MdeModulePkg.dec | 4 +-
> UefiCpuPkg/CpuDxe/CpuDxe.h | 39 +++
> UefiCpuPkg/CpuDxe/CpuDxe.inf | 3 +
> UefiCpuPkg/CpuDxe/CpuMp.c | 34 ++-
> UefiCpuPkg/CpuDxe/CpuPageTable.c | 271 +++++++++++++++++++++
> .../Ia32/ExceptionHandlerAsm.nasm | 7 +
> .../Ia32/ExceptionTssEntryAsm.nasm | 4 +-
> .../X64/ExceptionHandlerAsm.nasm | 4 +
> UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/PageTbl.c | 43 ++--
> UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.nasm | 3 +-
> UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfile.c | 58 ++++-
> UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfile.h | 15 ++
> UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfileInternal.h | 6 +
> UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c | 43 ++--
> 14 files changed, 493 insertions(+), 41 deletions(-)
>
(1) This looks like a feature addition, so please include the BZ
reference (1095) on the following wiki page:
https://github.com/tianocore/tianocore.github.io/wiki/EDK-II-Release-Planning
(under "Proposed Features")
[Jian] Sure. I’ll add it.
(2) The general description should be moved (or copied) from this email
(v2 0/4) to patch #1 (v2 1/4). The cover letter is not captured in the
commit log, and I think there isn't going to be any other documentation
for the feature than the DEC file.
(Note that I'm not suggesting that you add the documentation to the DEC
file in patch #1 -- instead, the commit message on patch #1 should
contain it. Then people can find the commit from the DEC file with "git
blame", and read the description.)
[Jian] You’re right. I forgot this point. I’ll copy it. Thanks.
Thanks
Laszlo
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2 3/4] UefiCpuPkg/CpuDxe: implement non-stop mode for uefi
2018-08-21 14:58 ` Laszlo Ersek
@ 2018-08-22 7:13 ` Wang, Jian J
2018-08-22 7:45 ` Laszlo Ersek
0 siblings, 1 reply; 15+ messages in thread
From: Wang, Jian J @ 2018-08-22 7:13 UTC (permalink / raw)
To: Laszlo Ersek, edk2-devel@lists.01.org; +Cc: Ni, Ruiyu, Dong, Eric
Hi Laszlo,
Regards,
Jian
From: Laszlo Ersek [mailto:lersek@redhat.com]
Sent: Tuesday, August 21, 2018 10:59 PM
To: Wang, Jian J <jian.j.wang@intel.com>; edk2-devel@lists.01.org
Cc: Ni, Ruiyu <ruiyu.ni@intel.com>; Dong, Eric <eric.dong@intel.com>
Subject: Re: [edk2] [PATCH v2 3/4] UefiCpuPkg/CpuDxe: implement non-stop mode for uefi
I only have some superficial comments here.
On 08/21/18 05:05, Jian J Wang wrote:
>> v2 changes:
>> n/a
>
> 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<mailto:eric.dong@intel.com>>
> Cc: Laszlo Ersek <lersek@redhat.com<mailto:lersek@redhat.com>>
> Cc: Ruiyu Ni <ruiyu.ni@intel.com<mailto:ruiyu.ni@intel.com>>
> Contributed-under: TianoCore Contribution Agreement 1.1
> Signed-off-by: Jian J Wang <jian.j.wang@intel.com<mailto:jian.j.wang@intel.com>>
> ---
> UefiCpuPkg/CpuDxe/CpuDxe.h | 39 ++++++
> UefiCpuPkg/CpuDxe/CpuDxe.inf | 3 +
> UefiCpuPkg/CpuDxe/CpuMp.c | 34 ++++-
> UefiCpuPkg/CpuDxe/CpuPageTable.c | 271 +++++++++++++++++++++++++++++++++++++++
> 4 files changed, 341 insertions(+), 6 deletions(-)
>
> diff --git a/UefiCpuPkg/CpuDxe/CpuDxe.h b/UefiCpuPkg/CpuDxe/CpuDxe.h
> index 540f5f2dbf..7d65e39e90 100644
> --- a/UefiCpuPkg/CpuDxe/CpuDxe.h
> +++ b/UefiCpuPkg/CpuDxe/CpuDxe.h
> @@ -57,6 +57,12 @@
> 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
> with all DMA operations then function can just return EFI_SUCCESS.
> @@ -273,7 +279,40 @@ RefreshGcdMemoryAttributesFromPaging (
> 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 UINTN mNumberOfProcessors;
>
> #endif
>
> diff --git a/UefiCpuPkg/CpuDxe/CpuDxe.inf b/UefiCpuPkg/CpuDxe/CpuDxe.inf
> index 6a199b72f7..97a381b046 100644
> --- a/UefiCpuPkg/CpuDxe/CpuDxe.inf
> +++ b/UefiCpuPkg/CpuDxe/CpuDxe.inf
> @@ -46,6 +46,7 @@
> ReportStatusCodeLib
> MpInitLib
> TimerLib
> + PeCoffGetEntryPointLib
>
> [Sources]
> CpuDxe.c
> @@ -79,6 +80,8 @@
> [Pcd]
> gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask ## CONSUMES
> gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard ## CONSUMES
> + gEfiMdeModulePkgTokenSpaceGuid.PcdHeapGuardPropertyMask ## CONSUMES
> + gEfiMdeModulePkgTokenSpaceGuid.PcdNullPointerDetectionPropertyMask ## CONSUMES
> gUefiCpuPkgTokenSpaceGuid.PcdCpuStackSwitchExceptionList ## CONSUMES
> gUefiCpuPkgTokenSpaceGuid.PcdCpuKnownGoodStackSize ## CONSUMES
>
> diff --git a/UefiCpuPkg/CpuDxe/CpuMp.c b/UefiCpuPkg/CpuDxe/CpuMp.c
> index 82145e7624..f8489eb1c3 100644
> --- a/UefiCpuPkg/CpuDxe/CpuMp.c
> +++ b/UefiCpuPkg/CpuDxe/CpuMp.c
> @@ -673,10 +673,6 @@ InitializeMpExceptionStackSwitchHandlers (
> UINT8 *GdtBuffer;
> UINT8 *StackTop;
>
> - if (!PcdGetBool (PcdCpuStackGuard)) {
> - return;
> - }
> -
> ExceptionNumber = FixedPcdGetSize (PcdCpuStackSwitchExceptionList);
> 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.
>
> @@ -814,9 +836,9 @@ InitializeMpSupport (
> 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
The reworking of the InitializeMpExceptionStackSwitchHandlers() /
PcdGetBool (PcdCpuStackGuard) call sites look OK to me.
(1) However, some whitespace is missing before opening parentheses. See
eg. after "RegisterCpuInterruptHandler".
Please check the rest of the code for that as well.
[Jian] Sure. I’ll check it.
> diff --git a/UefiCpuPkg/CpuDxe/CpuPageTable.c b/UefiCpuPkg/CpuDxe/CpuPageTable.c
> index df021798c0..b65f74bd72 100644
> --- a/UefiCpuPkg/CpuDxe/CpuPageTable.c
> +++ b/UefiCpuPkg/CpuDxe/CpuPageTable.c
> @@ -22,6 +22,10 @@
> #include <Library/MemoryAllocationLib.h>
> #include <Library/DebugLib.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/SmmBase2.h>
> #include <Register/Cpuid.h>
> @@ -73,6 +77,10 @@
> #define PAGING_2M_ADDRESS_MASK_64 0x000FFFFFFFE00000ull
> #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 {
> PageNone,
> Page4K,
> @@ -102,6 +110,13 @@ PAGE_TABLE_POOL *mPageTablePool = NULL;
> PAGE_TABLE_LIB_PAGING_CONTEXT mPagingContext;
> EFI_SMM_BASE2_PROTOCOL *mSmmBase2 = NULL;
>
> +//
> +// Record the page fault exception count for one instruction execution.
> +//
> +UINTN *mPFEntryCount;
> +UINT64 (*mLastPFEntryValue)[MAX_PF_ENTRY_COUNT];
(2) "mLastPFEntryValue" seems unused.
[Jian] You’re right. It should be removed.
> +UINT64 *(*mLastPFEntryPointer)[MAX_PF_ENTRY_COUNT];
(3) I think mPFEntryCount and mLastPFEntryPointer could be made STATIC.
(Not sure if that's consistent with the rest of the variable definitions
though, in this file.)
[Jian] I double checked. No STATIC used. So let’s keep it as is.
> +
> /**
> Check if current execution environment is in SMM mode or not, via
> EFI_SMM_BASE2_PROTOCOL.
> @@ -1135,6 +1150,253 @@ AllocatePageTableMemory (
> return Buffer;
> }
>
> +/**
> + Prints a message to the serial port.
> +
> + @param Format Format string for the message to print.
> + @param ... Variable argument list whose contents are accessed
> + based on the format string specified by Format.
> +
> +**/
> +STATIC
> +VOID
> +EFIAPI
> +InternalPrintMessage (
> + IN CONST CHAR8 *Format,
> + ...
> + )
> +{
> + CHAR8 Buffer[MAX_DEBUG_MESSAGE_LENGTH];
> + VA_LIST Marker;
> +
> + //
> + // Convert the message to an ASCII String
> + //
> + VA_START (Marker, Format);
> + AsciiVSPrint (Buffer, sizeof (Buffer), Format, Marker);
> + VA_END (Marker);
> +
> + //
> + // Send the print string to a Serial Port
> + //
> + SerialPortWrite ((UINT8 *)Buffer, AsciiStrLen (Buffer));
> +}
> +
> +/**
> + Find and display image base address and return image base and its entry point.
> +
> + @param CurrentIp Current instruction pointer.
> +
> +**/
> +STATIC
> +VOID
> +DumpModuleImageInfo (
> + IN UINTN CurrentIp
> + )
> +{
> + EFI_STATUS Status;
> + UINTN Pe32Data;
> + VOID *PdbPointer;
> + VOID *EntryPoint;
> +
> + Pe32Data = PeCoffSearchImageBase (CurrentIp);
> + if (Pe32Data == 0) {
> + InternalPrintMessage ("!!!! Can't find image information. !!!!\n");
> + } else {
> + //
> + // Find Image Base entry point
> + //
> + Status = PeCoffLoaderGetEntryPoint ((VOID *) Pe32Data, &EntryPoint);
> + if (EFI_ERROR (Status)) {
> + EntryPoint = NULL;
> + }
> + InternalPrintMessage ("!!!! Find image based on IP(0x%x) ", CurrentIp);
> + PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *) Pe32Data);
> + if (PdbPointer != NULL) {
> + InternalPrintMessage ("%a", PdbPointer);
> + } else {
> + InternalPrintMessage ("(No PDB) " );
> + }
> + InternalPrintMessage (
> + " (ImageBase=%016lp, EntryPoint=%016p) !!!!\n",
> + (VOID *) Pe32Data,
> + EntryPoint
> + );
> + }
> +}
(4) Why is this function copied here? From a quick check, it looks
identical to DumpModuleImageInfo() in
"UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c".
And, DumpModuleImageInfo() is an extern function in
"UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h", and we
are (likely) already linking against that library instance. As a result
we'll have the same function twice in CpuDxe, once as STATIC, and
another time as extern.
If this is a useful utility function, then it should be elevated to a
public library API, and used from there. (I don't know where to add it,
I just find this code duplication regrettable.)
[Jian] I reviewed the whole working model again. I think we don’t need to dump
the image information here, because, if there’s an issue detected, the developers
will disable the non-stop mode anyway in order to find the root cause. Then the
image information can be dumped (normal mode). So we can just dump cpu
information to tell the user that there’s an exception here. And dumping cpu
information is already a public interface so we don’t need to duplicate any code
here.
Thanks
Laszlo
> +
> +/**
> + 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;
> + UINTN CurrentIp;
> + 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);
> + //
> + // Dump module image base and module entry point by RIP
> + //
> + if (mPagingContext.MachineType == IMAGE_FILE_MACHINE_I386) {
> + if ((SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_ID) != 0) {
> + //
> + // The EIP in SystemContext could not be used
> + // if it is page fault with I/D set.
> + //
> + CurrentIp = *(UINTN *)(UINTN)SystemContext.SystemContextIa32->Esp;
> + } else {
> + CurrentIp = (UINTN)SystemContext.SystemContextIa32->Eip;
> + }
> + } else {
> + if ((SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_ID) != 0) {
> + //
> + // The RIP in SystemContext could not be used
> + // if it is page fault with I/D set.
> + //
> + CurrentIp = *(UINTN *)(UINTN)SystemContext.SystemContextX64->Rsp;
> + } else {
> + CurrentIp = (UINTN)SystemContext.SystemContextX64->Rip;
> + }
> + }
> +
> + DumpModuleImageInfo (CurrentIp);
> +
> + if (!NonStopMode) {
> + CpuDeadLoop();
> + }
> +}
> +
> /**
> Initialize the Page Table lib.
> **/
> @@ -1158,6 +1420,15 @@ InitializePageTableLib (
> 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, " MachineType - 0x%x\n", CurrentPagingContext.MachineType));
> DEBUG ((DEBUG_INFO, " PageTableBase - 0x%x\n", CurrentPagingContext.ContextData.X64.PageTableBase));
>
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2 4/4] UefiCpuPkg/PiSmmCpuDxeSmm: implement non-stop mode for SMM
2018-08-21 15:44 ` Laszlo Ersek
@ 2018-08-22 7:16 ` Wang, Jian J
0 siblings, 0 replies; 15+ messages in thread
From: Wang, Jian J @ 2018-08-22 7:16 UTC (permalink / raw)
To: Laszlo Ersek, edk2-devel@lists.01.org; +Cc: Ni, Ruiyu, Dong, Eric
Hi Laszlo,
Thanks.
Regards,
Jian
From: Laszlo Ersek [mailto:lersek@redhat.com]
Sent: Tuesday, August 21, 2018 11:45 PM
To: Wang, Jian J <jian.j.wang@intel.com>; edk2-devel@lists.01.org
Cc: Ni, Ruiyu <ruiyu.ni@intel.com>; Dong, Eric <eric.dong@intel.com>
Subject: Re: [edk2] [PATCH v2 4/4] UefiCpuPkg/PiSmmCpuDxeSmm: implement non-stop mode for SMM
On 08/21/18 05:05, Jian J Wang wrote:
>> v2 changes:
>> fix GCC build error caused by an unused variable in GuardPagePFHandler()
>
> 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<mailto:eric.dong@intel.com>>
> Cc: Laszlo Ersek <lersek@redhat.com<mailto:lersek@redhat.com>>
> Cc: Ruiyu Ni <ruiyu.ni@intel.com<mailto:ruiyu.ni@intel.com>>
> Contributed-under: TianoCore Contribution Agreement 1.1
> Signed-off-by: Jian J Wang <jian.j.wang@intel.com<mailto:jian.j.wang@intel.com>>
> ---
> UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/PageTbl.c | 43 ++++++++++++------
> UefiCpuPkg/PiSmmCpuDxeSmm/Ia32/SmiException.nasm | 3 +-
> UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfile.c | 58 +++++++++++++++++++++++-
> UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfile.h | 15 ++++++
> UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfileInternal.h | 6 +++
> UefiCpuPkg/PiSmmCpuDxeSmm/X64/PageTbl.c | 43 ++++++++++++------
> 6 files changed, 137 insertions(+), 31 deletions(-)
It seems like the changes are no-ops for platforms that set all these
PCDs to zero, so from my side
Acked-by: Laszlo Ersek <lersek@redhat.com<mailto:lersek@redhat.com>>
Thanks
Laszlo
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2 3/4] UefiCpuPkg/CpuDxe: implement non-stop mode for uefi
2018-08-22 7:13 ` Wang, Jian J
@ 2018-08-22 7:45 ` Laszlo Ersek
0 siblings, 0 replies; 15+ messages in thread
From: Laszlo Ersek @ 2018-08-22 7:45 UTC (permalink / raw)
To: Wang, Jian J, edk2-devel@lists.01.org; +Cc: Ni, Ruiyu, Dong, Eric
On 08/22/18 09:13, Wang, Jian J wrote:
> Hi Laszlo,
>
> Regards,
> Jian
>
> From: Laszlo Ersek [mailto:lersek@redhat.com]
> Sent: Tuesday, August 21, 2018 10:59 PM
> To: Wang, Jian J <jian.j.wang@intel.com>; edk2-devel@lists.01.org
> Cc: Ni, Ruiyu <ruiyu.ni@intel.com>; Dong, Eric <eric.dong@intel.com>
> Subject: Re: [edk2] [PATCH v2 3/4] UefiCpuPkg/CpuDxe: implement non-stop mode for uefi
>> +/**
>> + Find and display image base address and return image base and its entry point.
>> +
>> + @param CurrentIp Current instruction pointer.
>> +
>> +**/
>> +STATIC
>> +VOID
>> +DumpModuleImageInfo (
>> + IN UINTN CurrentIp
>> + )
>> +{
>> + EFI_STATUS Status;
>> + UINTN Pe32Data;
>> + VOID *PdbPointer;
>> + VOID *EntryPoint;
>> +
>> + Pe32Data = PeCoffSearchImageBase (CurrentIp);
>> + if (Pe32Data == 0) {
>> + InternalPrintMessage ("!!!! Can't find image information. !!!!\n");
>> + } else {
>> + //
>> + // Find Image Base entry point
>> + //
>> + Status = PeCoffLoaderGetEntryPoint ((VOID *) Pe32Data, &EntryPoint);
>> + if (EFI_ERROR (Status)) {
>> + EntryPoint = NULL;
>> + }
>> + InternalPrintMessage ("!!!! Find image based on IP(0x%x) ", CurrentIp);
>> + PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *) Pe32Data);
>> + if (PdbPointer != NULL) {
>> + InternalPrintMessage ("%a", PdbPointer);
>> + } else {
>> + InternalPrintMessage ("(No PDB) " );
>> + }
>> + InternalPrintMessage (
>> + " (ImageBase=%016lp, EntryPoint=%016p) !!!!\n",
>> + (VOID *) Pe32Data,
>> + EntryPoint
>> + );
>> + }
>> +}
>
> (4) Why is this function copied here? From a quick check, it looks
> identical to DumpModuleImageInfo() in
> "UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c".
>
> And, DumpModuleImageInfo() is an extern function in
> "UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h", and we
> are (likely) already linking against that library instance. As a result
> we'll have the same function twice in CpuDxe, once as STATIC, and
> another time as extern.
>
> If this is a useful utility function, then it should be elevated to a
> public library API, and used from there. (I don't know where to add it,
> I just find this code duplication regrettable.)
>
> [Jian] I reviewed the whole working model again. I think we don’t need to dump
> the image information here, because, if there’s an issue detected, the developers
> will disable the non-stop mode anyway in order to find the root cause. Then the
> image information can be dumped (normal mode). So we can just dump cpu
> information to tell the user that there’s an exception here. And dumping cpu
> information is already a public interface so we don’t need to duplicate any code
> here.
Oh cool. If we can eliminate the function altogether, that's best.
Thanks!
Laszlo
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2 2/4] UefiCpuPkg/CpuExceptionHandlerLib: Setup single step in #PF handler
2018-08-21 3:05 ` [PATCH v2 2/4] UefiCpuPkg/CpuExceptionHandlerLib: Setup single step in #PF handler Jian J Wang
2018-08-21 14:39 ` Laszlo Ersek
@ 2018-08-28 1:14 ` Dong, Eric
2018-08-28 3:24 ` Wang, Jian J
1 sibling, 1 reply; 15+ messages in thread
From: Dong, Eric @ 2018-08-28 1:14 UTC (permalink / raw)
To: Wang, Jian J, edk2-devel@lists.01.org; +Cc: Laszlo Ersek, Ni, Ruiyu
Reviewed-by: Eric Dong <eric.dong@intel.com>
> -----Original Message-----
> From: Wang, Jian J
> Sent: Tuesday, August 21, 2018 11:05 AM
> To: edk2-devel@lists.01.org
> Cc: Dong, Eric <eric.dong@intel.com>; Laszlo Ersek <lersek@redhat.com>; Ni,
> Ruiyu <ruiyu.ni@intel.com>
> Subject: [PATCH v2 2/4] UefiCpuPkg/CpuExceptionHandlerLib: Setup single
> step in #PF handler
>
> > v2 changes:
> > n/a
>
> Once the #PF handler has set the page to be 'present', there should be a way
> to reset it to 'not-present'. 'TF' bit in EFLAGS can be used for this purpose. 'TF'
> bit will be set in interrupted function context so that it can be triggered once
> the cpu control returns back to the instruction causing #PF and re-execute it.
>
> This is an necessary step to implement non-stop mode for 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>
> ---
> .../Library/CpuExceptionHandlerLib/Ia32/ExceptionHandlerAsm.nasm | 7
> +++++++
> .../Library/CpuExceptionHandlerLib/Ia32/ExceptionTssEntryAsm.nasm | 4 +--
> -
> .../Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.nasm | 4
> ++++
> 3 files changed, 12 insertions(+), 3 deletions(-)
>
> diff --git
> a/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionHandlerAsm.na
> sm
> b/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionHandlerAsm.na
> sm
> index 45d6474091..6fcf5fb23f 100644
> ---
> a/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionHandlerAsm.na
> sm
> +++
> b/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionHandlerAsm
> +++ .nasm
> @@ -383,6 +383,13 @@ ErrorCodeAndVectorOnStack:
> pop dword [ebp - 4]
> mov esp, ebp
> pop ebp
> +
> +; Enable TF bit after page fault handler runs
> + cmp dword [esp], 14 ; #PF?
> + jne .5
> + bts dword [esp + 16], 8 ; EFLAGS
> +
> +.5:
> add esp, 8
> cmp dword [esp - 16], 0 ; check
> EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
> jz DoReturn
> diff --git
> a/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionTssEntryAsm.n
> asm
> b/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionTssEntryAsm.n
> asm
> index 62bcedea1a..7aac29c7e7 100644
> ---
> a/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionTssEntryAsm.n
> asm
> +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionTssEntryAs
> +++ m.nasm
> @@ -355,10 +355,8 @@ o16 mov [ecx + IA32_TSS._SS], ax
> movzx ebx, word [ecx + IA32_TSS._CS]
> mov [eax - 0x8], ebx ; create CS in old stack
> mov ebx, dword [ecx + IA32_TSS.EFLAGS]
> - bts ebx, 8
> + bts ebx, 8 ; Set TF
> mov [eax - 0x4], ebx ; create eflags in old stack
> - mov dword [ecx + IA32_TSS.EFLAGS], ebx ; update eflags in old TSS
> - mov eax, dword [ecx + IA32_TSS._ESP] ; Get old stack pointer
> sub eax, 0xc ; minus 12 byte
> mov dword [ecx + IA32_TSS._ESP], eax ; Set new stack pointer
>
> diff --git
> a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.na
> sm
> b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.na
> sm
> index 7b97810d10..f842af2336 100644
> ---
> a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.na
> sm
> +++
> b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.
> +++ nasm
> @@ -336,6 +336,10 @@ HasErrorCode:
> pop r15
>
> mov rsp, rbp
> + cmp qword [rbp + 8], 14 ; #PF?
> + jne .1
> + bts qword [rsp + 40], 8 ; RFLAGS.TF
> +.1:
> pop rbp
> add rsp, 16
> cmp qword [rsp - 32], 0 ; check
> EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
> --
> 2.16.2.windows.1
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2 2/4] UefiCpuPkg/CpuExceptionHandlerLib: Setup single step in #PF handler
2018-08-28 1:14 ` Dong, Eric
@ 2018-08-28 3:24 ` Wang, Jian J
0 siblings, 0 replies; 15+ messages in thread
From: Wang, Jian J @ 2018-08-28 3:24 UTC (permalink / raw)
To: Dong, Eric, edk2-devel@lists.01.org; +Cc: Laszlo Ersek, Ni, Ruiyu
Thanks. Since there're just some minor changes, I'll not provide v3 patches
and push the changes to master soon.
Regards,
Jian
From: Dong, Eric
Sent: Tuesday, August 28, 2018 9:15 AM
To: Wang, Jian J <jian.j.wang@intel.com>; edk2-devel@lists.01.org
Cc: Laszlo Ersek <lersek@redhat.com>; Ni, Ruiyu <ruiyu.ni@intel.com>
Subject: RE: [PATCH v2 2/4] UefiCpuPkg/CpuExceptionHandlerLib: Setup single step in #PF handler
Reviewed-by: Eric Dong <eric.dong@intel.com<mailto:eric.dong@intel.com>>
> -----Original Message-----
> From: Wang, Jian J
> Sent: Tuesday, August 21, 2018 11:05 AM
> To: edk2-devel@lists.01.org<mailto:edk2-devel@lists.01.org>
> Cc: Dong, Eric <eric.dong@intel.com<mailto:eric.dong@intel.com>>; Laszlo Ersek <lersek@redhat.com<mailto:lersek@redhat.com>>; Ni,
> Ruiyu <ruiyu.ni@intel.com<mailto:ruiyu.ni@intel.com>>
> Subject: [PATCH v2 2/4] UefiCpuPkg/CpuExceptionHandlerLib: Setup single
> step in #PF handler
>
> > v2 changes:
> > n/a
>
> Once the #PF handler has set the page to be 'present', there should be a way
> to reset it to 'not-present'. 'TF' bit in EFLAGS can be used for this purpose. 'TF'
> bit will be set in interrupted function context so that it can be triggered once
> the cpu control returns back to the instruction causing #PF and re-execute it.
>
> This is an necessary step to implement non-stop mode for Heap Guard and
> NULL Pointer Detection feature.
>
> Cc: Eric Dong <eric.dong@intel.com<mailto:eric.dong@intel.com>>
> Cc: Laszlo Ersek <lersek@redhat.com<mailto:lersek@redhat.com>>
> Cc: Ruiyu Ni <ruiyu.ni@intel.com<mailto:ruiyu.ni@intel.com>>
> Contributed-under: TianoCore Contribution Agreement 1.1
> Signed-off-by: Jian J Wang <jian.j.wang@intel.com<mailto:jian.j.wang@intel.com>>
> ---
> .../Library/CpuExceptionHandlerLib/Ia32/ExceptionHandlerAsm.nasm | 7
> +++++++
> .../Library/CpuExceptionHandlerLib/Ia32/ExceptionTssEntryAsm.nasm | 4 +--
> -
> .../Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.nasm | 4
> ++++
> 3 files changed, 12 insertions(+), 3 deletions(-)
>
> diff --git
> a/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionHandlerAsm.na
> sm
> b/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionHandlerAsm.na
> sm
> index 45d6474091..6fcf5fb23f 100644
> ---
> a/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionHandlerAsm.na
> sm
> +++
> b/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionHandlerAsm
> +++ .nasm
> @@ -383,6 +383,13 @@ ErrorCodeAndVectorOnStack:
> pop dword [ebp - 4]
> mov esp, ebp
> pop ebp
> +
> +; Enable TF bit after page fault handler runs
> + cmp dword [esp], 14 ; #PF?
> + jne .5
> + bts dword [esp + 16], 8 ; EFLAGS
> +
> +.5:
> add esp, 8
> cmp dword [esp - 16], 0 ; check
> EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
> jz DoReturn
> diff --git
> a/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionTssEntryAsm.n
> asm
> b/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionTssEntryAsm.n
> asm
> index 62bcedea1a..7aac29c7e7 100644
> ---
> a/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionTssEntryAsm.n
> asm
> +++ b/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionTssEntryAs
> +++ m.nasm
> @@ -355,10 +355,8 @@ o16 mov [ecx + IA32_TSS._SS], ax
> movzx ebx, word [ecx + IA32_TSS._CS]
> mov [eax - 0x8], ebx ; create CS in old stack
> mov ebx, dword [ecx + IA32_TSS.EFLAGS]
> - bts ebx, 8
> + bts ebx, 8 ; Set TF
> mov [eax - 0x4], ebx ; create eflags in old stack
> - mov dword [ecx + IA32_TSS.EFLAGS], ebx ; update eflags in old TSS
> - mov eax, dword [ecx + IA32_TSS._ESP] ; Get old stack pointer
> sub eax, 0xc ; minus 12 byte
> mov dword [ecx + IA32_TSS._ESP], eax ; Set new stack pointer
>
> diff --git
> a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.na
> sm
> b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.na
> sm
> index 7b97810d10..f842af2336 100644
> ---
> a/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.na
> sm
> +++
> b/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.
> +++ nasm
> @@ -336,6 +336,10 @@ HasErrorCode:
> pop r15
>
> mov rsp, rbp
> + cmp qword [rbp + 8], 14 ; #PF?
> + jne .1
> + bts qword [rsp + 40], 8 ; RFLAGS.TF
> +.1:
> pop rbp
> add rsp, 16
> cmp qword [rsp - 32], 0 ; check
> EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
> --
> 2.16.2.windows.1
^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2018-08-28 3:28 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2018-08-21 3:05 [PATCH v2 0/4] Support non-stop mode in heap guard and null detection Jian J Wang
2018-08-21 3:05 ` [PATCH v2 1/4] MdeModulePkg/MdeModulePkg.dec: add new settings for PCDs Jian J Wang
2018-08-21 3:05 ` [PATCH v2 2/4] UefiCpuPkg/CpuExceptionHandlerLib: Setup single step in #PF handler Jian J Wang
2018-08-21 14:39 ` Laszlo Ersek
2018-08-28 1:14 ` Dong, Eric
2018-08-28 3:24 ` Wang, Jian J
2018-08-21 3:05 ` [PATCH v2 3/4] UefiCpuPkg/CpuDxe: implement non-stop mode for uefi Jian J Wang
2018-08-21 14:58 ` Laszlo Ersek
2018-08-22 7:13 ` Wang, Jian J
2018-08-22 7:45 ` Laszlo Ersek
2018-08-21 3:05 ` [PATCH v2 4/4] UefiCpuPkg/PiSmmCpuDxeSmm: implement non-stop mode for SMM Jian J Wang
2018-08-21 15:44 ` Laszlo Ersek
2018-08-22 7:16 ` Wang, Jian J
2018-08-21 14:28 ` [PATCH v2 0/4] Support non-stop mode in heap guard and null detection Laszlo Ersek
2018-08-22 6:59 ` Wang, Jian J
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox