[NTOS:KE] Improvements for the Trap02 (NMI) and Trap08 (double-fault) exception handlers.
authorHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Mon, 4 Feb 2019 00:16:29 +0000 (01:16 +0100)
committerHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Thu, 20 Jun 2019 17:38:56 +0000 (19:38 +0200)
- Add FRAME_TSS FPO debug information for Trap02 and Trap08.
- Switch the active TSS in Trap08 in the very same way as is done in Trap02.

This allows to correctly debug NMI and double-fault exceptions with WinDbg,
by following the different TSS contexts, as described in:
https://blogs.msdn.microsoft.com/debuggingtoolbox/2008/02/22/special-command-analyzing-and-reconstructing-the-stack-using-the-k-command-and-its-variations/
https://blogs.msdn.microsoft.com/ntdebugging/2009/11/25/part-1-got-stack-no-we-ran-out-of-kernel-mode-stack-and-kv-wont-tell-me-why/
http://www.osronline.com/article.cfm?article=254 and http://www.osronline.com/article.cfm?article=328

ntoskrnl/include/internal/i386/asmmacro.S
ntoskrnl/include/internal/i386/ke.h
ntoskrnl/ke/i386/trap.s
ntoskrnl/ke/i386/traphdlr.c

index 6d2d213..57f83b7 100644 (file)
@@ -249,6 +249,22 @@ MACRO(TRAP_ENTRY, Trap, Flags)
     .ENDP
 ENDM
 
+MACRO(TASK_ENTRY, Trap, Flags)
+    // EXTERN @&Trap&Handler@0 :PROC
+    EXTERN _&Trap&Handler :PROC
+    PUBLIC _&Trap
+    .PROC _&Trap
+        /* Generate proper debugging symbols */
+        FPO 0, 0, 0, 0, 0, FRAME_TSS
+
+        // /* Common code to create the trap frame */
+        // KiEnterTrap Flags
+
+        /* Call the C handler */
+        KiCallHandler _&Trap&Handler // @&Trap&Handler@0
+    .ENDP
+ENDM
+
 #define KI_RESTORE_EAX        HEX(0001)
 #define KI_RESTORE_ECX_EDX    HEX(0002)
 #define KI_RESTORE_FS         HEX(0004)
index 10eb6eb..7ce491e 100644 (file)
@@ -575,7 +575,7 @@ extern ULONG KeI386CpuStep;
 extern ULONG KiFastSystemCallDisable;
 extern UCHAR KiDebugRegisterTrapOffsets[9];
 extern UCHAR KiDebugRegisterContextOffsets[9];
-extern DECLSPEC_NORETURN VOID __cdecl KiTrap02(VOID);
+extern VOID __cdecl KiTrap02(VOID);
 extern VOID __cdecl KiTrap08(VOID);
 extern VOID __cdecl KiTrap13(VOID);
 extern VOID __cdecl KiFastCallEntry(VOID);
index 6bd57e8..d70ff66 100644 (file)
@@ -27,8 +27,6 @@ _KiUnexpectedInterrupt&Vector:
 //.endfunc
 ENDM
 
-EXTERN _KiTrap02:PROC
-
 /* GLOBALS *******************************************************************/
 
 .data
@@ -99,12 +97,13 @@ ENDR
 
 TRAP_ENTRY KiTrap00, KI_PUSH_FAKE_ERROR_CODE
 TRAP_ENTRY KiTrap01, KI_PUSH_FAKE_ERROR_CODE
+TASK_ENTRY KiTrap02, 0
 TRAP_ENTRY KiTrap03, KI_PUSH_FAKE_ERROR_CODE
 TRAP_ENTRY KiTrap04, KI_PUSH_FAKE_ERROR_CODE
 TRAP_ENTRY KiTrap05, KI_PUSH_FAKE_ERROR_CODE
 TRAP_ENTRY KiTrap06, KI_PUSH_FAKE_ERROR_CODE
 TRAP_ENTRY KiTrap07, KI_PUSH_FAKE_ERROR_CODE
-TRAP_ENTRY KiTrap08, 0
+TASK_ENTRY KiTrap08, 0
 TRAP_ENTRY KiTrap09, KI_PUSH_FAKE_ERROR_CODE
 TRAP_ENTRY KiTrap0A, 0
 TRAP_ENTRY KiTrap0B, 0
index 7cf1fcd..863641b 100644 (file)
@@ -458,7 +458,7 @@ KiTrap01Handler(IN PKTRAP_FRAME TrapFrame)
 DECLSPEC_NORETURN
 VOID
 __cdecl
-KiTrap02(VOID)
+KiTrap02Handler(VOID)
 {
     PKTSS Tss, NmiTss;
     PKTHREAD Thread;
@@ -829,11 +829,53 @@ KiTrap07Handler(IN PKTRAP_FRAME TrapFrame)
 
 DECLSPEC_NORETURN
 VOID
-FASTCALL
-KiTrap08Handler(IN PKTRAP_FRAME TrapFrame)
+__cdecl
+KiTrap08Handler(VOID)
 {
-    /* FIXME: Not handled */
-    KiSystemFatalException(EXCEPTION_DOUBLE_FAULT, TrapFrame);
+    PKTSS Tss, DfTss;
+    PKTHREAD Thread;
+    PKPROCESS Process;
+    PKGDTENTRY TssGdt;
+
+    /* For sanity's sake, make sure interrupts are disabled */
+    _disable();
+
+    /* Get the current TSS, thread, and process */
+    Tss = KeGetPcr()->TSS;
+    Thread = ((PKIPCR)KeGetPcr())->PrcbData.CurrentThread;
+    Process = Thread->ApcState.Process;
+
+    /* Save data usually not present in the TSS */
+    Tss->CR3 = Process->DirectoryTableBase[0];
+    Tss->IoMapBase = Process->IopmOffset;
+    Tss->LDT = Process->LdtDescriptor.LimitLow ? KGDT_LDT : 0;
+
+    /* Now get the base address of the double-fault TSS */
+    TssGdt = &((PKIPCR)KeGetPcr())->GDT[KGDT_DF_TSS / sizeof(KGDTENTRY)];
+    DfTss  = (PKTSS)(ULONG_PTR)(TssGdt->BaseLow |
+                                TssGdt->HighWord.Bytes.BaseMid << 16 |
+                                TssGdt->HighWord.Bytes.BaseHi << 24);
+
+    /*
+     * Switch to it and activate it, masking off the nested flag.
+     *
+     * Note that in reality, we are already on the double-fault TSS
+     * -- we just need to update the PCR to reflect this.
+     */
+    KeGetPcr()->TSS = DfTss;
+    __writeeflags(__readeflags() &~ EFLAGS_NESTED_TASK);
+    TssGdt->HighWord.Bits.Dpl = 0;
+    TssGdt->HighWord.Bits.Pres = 1;
+    // TssGdt->HighWord.Bits.Type &= ~0x2; /* I386_ACTIVE_TSS --> I386_TSS */
+    TssGdt->HighWord.Bits.Type = I386_TSS; // Busy bit cleared in the TSS selector.
+
+    /* Bugcheck the system */
+    KeBugCheckWithTf(UNEXPECTED_KERNEL_MODE_TRAP,
+                     EXCEPTION_DOUBLE_FAULT,
+                     (ULONG_PTR)Tss,
+                     0,
+                     0,
+                     NULL);
 }
 
 DECLSPEC_NORETURN