Author: ros-arm-bringup
Date: Sat Jan 2 02:34:27 2010
New Revision: 44871
URL:
http://svn.reactos.org/svn/reactos?rev=44871&view=rev
Log:
NMI Support Patch 10:
[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.
Modified:
trunk/reactos/ntoskrnl/ke/i386/cpu.c
trunk/reactos/ntoskrnl/ke/i386/trap.s
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] Sat Jan 2 02:34:27 2010
@@ -924,6 +924,26 @@
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 **********************************************************/
/*
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] Sat Jan 2 02:34:27 2010
@@ -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 @@
.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