#include <asm.h>
#include <internal/i386/asmmacro.S>
+#include <internal/i386/callconv.s>
.intel_syntax noprefix
#define Running 2
.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