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/…
==============================================================================
--- 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…
==============================================================================
--- 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?re…
==============================================================================
--- 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