Author: ros-arm-bringup
Date: Wed Jan  6 01:40:07 2010
New Revision: 44971

URL: http://svn.reactos.org/svn/reactos?rev=44971&view=rev
Log:
- Implement NMI handler in C instead of ASM.
- Tested with the "nmi 0" command in QEMU and NmiDbg.sys.


Modified:
    trunk/reactos/ntoskrnl/include/internal/ke.h
    trunk/reactos/ntoskrnl/ke/i386/cpu.c
    trunk/reactos/ntoskrnl/ke/i386/trap.s

Modified: trunk/reactos/ntoskrnl/include/internal/ke.h
URL: 
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/ke.h?rev=44971&r1=44970&r2=44971&view=diff
==============================================================================
--- trunk/reactos/ntoskrnl/include/internal/ke.h [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/include/internal/ke.h [iso-8859-1] Wed Jan  6 
01:40:07 2010
@@ -863,6 +863,10 @@
     PKTRAP_FRAME Tf
 );
 
+BOOLEAN
+NTAPI
+KiHandleNmi(VOID);
+
 VOID
 NTAPI
 KeFlushCurrentTb(VOID);

Modified: trunk/reactos/ntoskrnl/ke/i386/cpu.c
URL: 
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ke/i386/cpu.c?rev=44971&r1=44970&r2=44971&view=diff
==============================================================================
--- trunk/reactos/ntoskrnl/ke/i386/cpu.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/ke/i386/cpu.c [iso-8859-1] Wed Jan  6 01:40:07 2010
@@ -944,6 +944,154 @@
     KiSaveProcessorControlState(&Prcb->ProcessorState);
 }
 
+/* C TRAP HANDLERS 
************************************************************/
+
+BOOLEAN
+NTAPI
+KiNmiFault(IN PVOID InterruptStack)
+{
+    PKTSS Tss, NmiTss;
+    PKTHREAD Thread;
+    PKPROCESS Process;
+    PKGDTENTRY TssGdt;
+    KTRAP_FRAME TrapFrame;
+    KIRQL OldIrql;
+    
+    //
+    // In some sort of strange recursion case, we might end up here with the IF
+    // flag incorrectly on the interrupt frame -- during a normal NMI this 
would
+    // normally already be set.
+    //
+    // For sanity's sake, make sure interrupts are disabled for sure.
+    // NMIs will already be since the CPU does it for us.
+    //
+    _disable();
+
+    //
+    // Get the current TSS, thread, and process
+    //
+    Tss = PCR->TSS;
+    Thread = ((PKIPCR)PCR)->PrcbData.CurrentThread;
+    Process = Thread->ApcState.Process;
+    
+    //
+    // Save data usually not 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 NMI TSS
+    //
+    TssGdt = &((PKIPCR)KeGetPcr())->GDT[KGDT_NMI_TSS / sizeof(KGDTENTRY)];
+    NmiTss = (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 NMI tss -- we just need to
+    // update the PCR to reflect this
+    //      
+    PCR->TSS = NmiTss;
+    __writeeflags(__readeflags() &~ EFLAGS_NESTED_TASK);
+    TssGdt->HighWord.Bits.Dpl = 0;
+    TssGdt->HighWord.Bits.Pres = 1;
+    TssGdt->HighWord.Bits.Type = I386_TSS;
+    
+    //
+    // Now build the trap frame based on the original TSS
+    //
+    // The CPU does a hardware "Context switch" / task switch of sorts and so 
it
+    // takes care of saving our context in the normal TSS.
+    //
+    // We just have to go get the values...
+    //
+    RtlZeroMemory(&TrapFrame, sizeof(KTRAP_FRAME));
+    TrapFrame.HardwareSegSs = Tss->Ss0;
+    TrapFrame.HardwareEsp = Tss->Esp0;
+    TrapFrame.EFlags = Tss->EFlags;
+    TrapFrame.SegCs = Tss->Cs;
+    TrapFrame.Eip = Tss->Eip;
+    TrapFrame.Ebp = Tss->Ebp;
+    TrapFrame.Ebx = Tss->Ebx;
+    TrapFrame.Esi = Tss->Esi;
+    TrapFrame.Edi = Tss->Edi;
+    TrapFrame.SegFs = Tss->Fs;
+    TrapFrame.ExceptionList = PCR->Tib.ExceptionList;
+    TrapFrame.PreviousPreviousMode = -1;
+    TrapFrame.Eax = Tss->Eax;
+    TrapFrame.Ecx = Tss->Ecx;
+    TrapFrame.Edx = Tss->Edx;
+    TrapFrame.SegDs = Tss->Ds;
+    TrapFrame.SegEs = Tss->Es;
+    TrapFrame.SegGs = Tss->Gs;
+    TrapFrame.DbgEip = Tss->Eip;
+    TrapFrame.DbgEbp = Tss->Ebp;
+    
+    //
+    // Store the trap frame in the KPRCB
+    //
+    KiSaveProcessorState(&TrapFrame, NULL);
+    
+    //
+    // Call any registered NMI handlers and see if they handled it or not
+    //
+    if (!KiHandleNmi())
+    {
+        //
+        // They did not, so call the platform HAL routine to bugcheck the 
system
+        //
+        // Make sure the HAL believes it's running at HIGH IRQL... we can't use
+        // the normal APIs here as playing with the IRQL could change the 
system
+        // state
+        //
+        OldIrql = PCR->Irql;
+        PCR->Irql = HIGH_LEVEL;
+        HalHandleNMI(NULL);
+        PCR->Irql = OldIrql;
+    }
+
+    //
+    // Although the CPU disabled NMIs, we just did a BIOS Call, which could've
+    // totally changed things.
+    //
+    // We have to make sure we're still in our original NMI -- a nested NMI 
+    // will point back to the NMI TSS, and in that case we're hosed.
+    //
+    if (PCR->TSS->Backlink != KGDT_NMI_TSS)
+    {
+        //
+        // Restore original TSS
+        //
+        PCR->TSS = Tss;
+        
+        //
+        // Set it back to busy
+        //
+        TssGdt->HighWord.Bits.Dpl = 0;
+        TssGdt->HighWord.Bits.Pres = 1;
+        TssGdt->HighWord.Bits.Type = I386_ACTIVE_TSS;
+        
+        //
+        // Restore nested flag
+        //
+        __writeeflags(__readeflags() | EFLAGS_NESTED_TASK);
+        
+        //
+        // Handled, return from interrupt
+        //
+        return TRUE;
+    }
+    
+    //
+    // Unhandled: crash the system
+    //
+    return FALSE;
+}
+
 /* PUBLIC FUNCTIONS **********************************************************/
 
 /*

Modified: trunk/reactos/ntoskrnl/ke/i386/trap.s
URL: 
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ke/i386/trap.s?rev=44971&r1=44970&r2=44971&view=diff
==============================================================================
--- trunk/reactos/ntoskrnl/ke/i386/trap.s [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/ke/i386/trap.s [iso-8859-1] Wed Jan  6 01:40:07 2010
@@ -791,143 +791,24 @@
 .globl _KiTrap2
 .func KiTrap2
 _KiTrap2:
-       //
-       // 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
+    //
+    // Call the C handler
+    //
+    stdCall _KiNmiFault, esp                        // Handle it in C
+    or al, al                                       // Check if it got handled
+    jne 1f                                          // Resume from NMI
+
+    //
+    // Return from NMI
+    //
+    iretd                                           // Interrupt return
+    jmp _KiTrap2                                    // Handle recursion
 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
-
-       //
-       // Call Registered NMI handlers
-       //
-       stdCall _KiHandleNmi                                                    
// Call NMI handlers
-       or al, al                                                               
                // Check if any handled it
-       jne 1f                                                                  
                // Resume from NMI
-
-       //
-       // 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.
-       //
-1:
-    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
+    //
+    // Crash the system
+    //
+    mov eax, EXCEPTION_NMI                          // STOP fault code
+    jmp _KiSystemFatalException                     // Bugcheck helper
 .endfunc
 
 .func KiTrap3


Reply via email to