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