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.

svn path=/trunk/; revision=44871
This commit is contained in:
ReactOS Portable Systems Group 2010-01-02 01:34:27 +00:00
parent b1e02d2174
commit 0926ed6652
2 changed files with 152 additions and 2 deletions

View 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 **********************************************************/
/*

View 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:
//
// Don't allow any other NMIs to come in for now
//
cli // Disable interrupts
/* FIXME: This is an NMI, nothing like a normal exception */
mov eax, 2
//
// 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