NMI Support Patch 10:
authorReactOS Portable Systems Group <ros-arm-bringup@svn.reactos.org>
Sat, 2 Jan 2010 01:34:27 +0000 (01:34 +0000)
committerReactOS Portable Systems Group <ros-arm-bringup@svn.reactos.org>
Sat, 2 Jan 2010 01:34:27 +0000 (01:34 +0000)
    [NTOS]: Write barebones NMI Trap handler which does a TSS context switch to the NMI TSS and then calls the HAL NMI handler.
    [NTOS]: Implement KiSaveProcessorState for doing a PRCB context save/restore.

You should now be able to test the new NMI functionality by either building the circuit referenced in my e-mail and attaching it to your PCI bus, or by using "nmi 0" in the QEMU stdio console.

svn path=/trunk/; revision=44871

reactos/ntoskrnl/ke/i386/cpu.c
reactos/ntoskrnl/ke/i386/trap.s

index 760b9fb..700454b 100644 (file)
@@ -924,6 +924,26 @@ KeZeroPages(IN PVOID Address,
     RtlZeroMemory(Address, Size);
 }
 
+VOID
+NTAPI
+KiSaveProcessorState(IN PKTRAP_FRAME TrapFrame,
+                     IN PKEXCEPTION_FRAME ExceptionFrame)
+{
+    PKPRCB Prcb = KeGetCurrentPrcb();
+
+    //
+    // Save full context
+    //
+    Prcb->ProcessorState.ContextFrame.ContextFlags = CONTEXT_FULL |
+                                                     CONTEXT_DEBUG_REGISTERS;
+    KeTrapFrameToContext(TrapFrame, NULL, &Prcb->ProcessorState.ContextFrame);
+
+    //
+    // Save control registers
+    //
+    KiSaveProcessorControlState(&Prcb->ProcessorState);
+}
+
 /* PUBLIC FUNCTIONS **********************************************************/
 
 /*
index 0f53d39..7e968cd 100644 (file)
@@ -10,6 +10,7 @@
 
 #include <asm.h>
 #include <internal/i386/asmmacro.S>
+#include <internal/i386/callconv.s>
 .intel_syntax noprefix
 
 #define Running 2
@@ -790,9 +791,138 @@ V86Int1:
 .globl _KiTrap2
 .func KiTrap2
 _KiTrap2:
-
-    /* FIXME: This is an NMI, nothing like a normal exception */
-    mov eax, 2
+       //
+       // Don't allow any other NMIs to come in for now
+       //
+    cli                                                                                                // Disable interrupts
+
+       //
+       // Save current state data in registers
+       //
+    mov eax, PCR[KPCR_TSS]                                                     // Save KTSS
+    mov ecx, PCR[KPCR_CURRENT_THREAD]                          // Save ETHREAD
+    mov edi, [ecx+KTHREAD_APCSTATE_PROCESS]                    // Save EPROCESS
+
+       //
+       // Migrate state data to TSS
+       //
+    mov ecx, [edi+KPROCESS_DIRECTORY_TABLE_BASE]       // Page Directory Table
+    mov [eax+KTSS_CR3], ecx                                                    // Saved in CR3
+    mov cx, [edi+KPROCESS_IOPM_OFFSET]                         // IOPM Offset
+    mov [eax+KTSS_IOMAPBASE], cx                                       // Saved in IOPM Base
+    mov ecx, [edi+KPROCESS_LDT_DESCRIPTOR0]                    // Get LDT descriptor
+    test ecx, ecx                                                                      // Check if ne
+    jz 1f                                                                                      // Doesn't exist
+    mov cx, KGDT_LDT                                                           // Load LDT descriptor
+1:
+    mov [eax+KTSS_LDT], cx                                                     // Saved in LDT
+   
+       //
+       // Migrate to NMI TSS
+       //
+    push PCR[KPCR_TSS]                                                         // Save current TSS
+    mov eax, PCR[KPCR_GDT]                                                     // Get GDT
+    mov ch, [eax+KGDT_NMI_TSS+KGDT_BASE_HI]                    // Get High KTSS Base
+    mov cl, [eax+KGDT_NMI_TSS+KGDT_BASE_MID]           // Get Mid KTSS Base
+    shl ecx, 16                                                                                // Build Top KTSS Base
+    mov cx, [eax+KGDT_NMI_TSS+KGDT_BASE_LOW]           // Add Low KTSS Base
+    mov PCR[KPCR_TSS], ecx
+
+       //
+       // Clear nested flag and activate the NMI TSS
+       //
+    pushf                                                                                      // Get EFLAGS
+    and dword ptr [esp], ~EFLAGS_NESTED_TASK           // Clear nested task
+    popf                                                                                       // Set EFLAGS
+    mov ecx, PCR[KPCR_GDT]                                                     // Get GDT
+    lea eax, [ecx+KGDT_NMI_TSS]                                                // Get NMI TSS
+    mov byte ptr [eax+5], 0x89                                         // DPL 0, Present, NonBusy
+
+       //
+       // Build the trap frame and save it into the KPRCB
+       //
+    mov eax, [esp]                                                                     // KGDT_TSS from earlier
+    push 0                                                                                     // V86 segments
+    push 0                                                                                     // V86 segments
+    push 0                                                                                     // V86 segments
+    push 0                                                                                     // V86 segments
+    push [eax+KTSS_SS]                                                         // TSS fields -> Trap Frame
+    push [eax+KTSS_ESP]                                                                // TSS fields -> Trap Frame
+    push [eax+KTSS_EFLAGS]                                                     // TSS fields -> Trap Frame
+    push [eax+KTSS_CS]                                                         // TSS fields -> Trap Frame
+    push [eax+KTSS_EIP]                                                                // TSS fields -> Trap Frame
+    push 0                                                                                     // Error Code
+    push [eax+KTSS_EBP]                                                                // TSS fields -> Trap Frame
+    push [eax+KTSS_EBX]                                                                // TSS fields -> Trap Frame
+    push [eax+KTSS_ESI]                                                                // TSS fields -> Trap Frame
+    push [eax+KTSS_EDI]                                                                // TSS fields -> Trap Frame
+    push [eax+KTSS_FS]                                                         // TSS fields -> Trap Frame
+    push PCR[KPCR_EXCEPTION_LIST]                                      // SEH Handler from KPCR
+    push -1                                                                                    // Bogus previous mode
+    push [eax+KTSS_EAX]                                                                // TSS fields -> Trap Frame
+    push [eax+KTSS_ECX]                                                                // TSS fields -> Trap Frame
+    push [eax+KTSS_EDX]                                                                // TSS fields -> Trap Frame
+    push [eax+KTSS_DS]                                                         // TSS fields -> Trap Frame
+    push [eax+KTSS_ES]                                                         // TSS fields -> Trap Frame
+    push [eax+KTSS_GS]                                                         // TSS fields -> Trap Frame
+    push 0                                                                                     // Debug registers
+    push 0                                                                                     // Debug registers
+    push 0                                                                                     // Debug registers
+    push 0                                                                                     // Debug registers
+    push 0                                                                                     // Debug registers
+    push 0                                                                                     // Debug registers
+    push 0                                                                                     // Temp
+    push 0                                                                                     // Temp
+    push 0                                                                                     // Debug Pointer
+    push 0                                                                                     // Debug Marker
+    push [eax+KTSS_EIP]                                                                // Debug EIP
+    push [eax+KTSS_EBP]                                                                // Debug EBP
+       mov ebp, esp                                                                    // Set trap frame address
+       stdCall _KiSaveProcessorState, ebp, 0                   // Save to KPRCB CONTEXT
+
+       //
+       // BUGBUG: Call Registered NMI handlers
+       //
+
+       //
+       // Call the platform driver for NMI handling (panic, etc)
+       // Do this with IRQL at HIGH
+       //
+       push PCR[KPCR_IRQL]                                                             // Save real IRQL
+       mov dword ptr PCR[KPCR_IRQL], HIGH_LEVEL                // Force HIGH
+       stdCall _HalHandleNMI, 0                                                // Call the HAL
+       pop PCR[KPCR_IRQL]                                                              // Restore real IRQL
+
+       //
+       // In certain situations, nested NMIs can corrupt the TSS, making us lose
+       // the original context. If this happens, we have no choice but to panic.
+       //
+    mov eax, PCR[KPCR_TSS]                                                     // Get current TSS
+    cmp word ptr [eax], KGDT_NMI_TSS                           // Check who its points to
+    je 2f                                                                                      // Back to the NMI TSS crash
+
+       //
+       // Otherwise, recover the original state
+       //
+    add esp, KTRAP_FRAME_LENGTH                                                // Clear the trap frame
+    pop PCR[KPCR_TSS]                                                          // Restore original TSS
+    mov ecx, PCR[KPCR_GDT]                                                     // Get GDT
+    lea eax, [ecx+KGDT_TSS]                                                    // Get KTSS
+    mov byte ptr [eax+5], 0x8B                                         // DPL 0, Present, Busy
+    pushf                                                                                      // Get EFLAGS
+    or dword ptr [esp], EFLAGS_NESTED_TASK                     // Set nested flags
+    popf                                                                                       // Set EFLAGS
+
+       //
+       // Return from NMI
+       //
+    iretd                                                                                      // Interrupt return
+       jmp _KiTrap2                                                                    // Handle recursion
+2:
+       //
+       // Crash the system
+       //
+    mov eax, EXCEPTION_NMI
     jmp _KiSystemFatalException
 .endfunc