mirror of
https://github.com/reactos/reactos.git
synced 2025-02-24 01:15:09 +00:00
Trap Handlers in C Patch 8 of X:
[NTOS]: Implement KiCoprocessorError in C. [NTOS]: Make NMI handler fully C, now that the other parts are C too. [NTOS]: Delete more ASM macros and code that are now unused. svn path=/trunk/; revision=45040
This commit is contained in:
parent
2eab477b33
commit
2efed8ef89
5 changed files with 169 additions and 548 deletions
|
@ -113,28 +113,6 @@
|
|||
.asciz \Reason
|
||||
.endm
|
||||
|
||||
//
|
||||
// @name UNHANDLED_V86_PATH
|
||||
//
|
||||
// This macro prints out that the current code path is for unhandled VDM support
|
||||
//
|
||||
// @param None
|
||||
//
|
||||
// @remark None.
|
||||
//
|
||||
.macro UNHANDLED_V86_PATH
|
||||
/* Get EIP */
|
||||
call $+5
|
||||
|
||||
/* Print debug message */
|
||||
push offset _V86UnhandledMsg
|
||||
call _DbgPrint
|
||||
add esp, 8
|
||||
|
||||
/* Loop indefinitely */
|
||||
jmp $
|
||||
.endm
|
||||
|
||||
//
|
||||
// @name IDT
|
||||
//
|
||||
|
@ -276,58 +254,6 @@ _HalpHardwareInterrupt&Number:
|
|||
.endr
|
||||
.endm
|
||||
|
||||
//
|
||||
// @name INVALID_V86_OPCODE
|
||||
//
|
||||
// This macro creates one or more entries for unhandled V86 Opcodes
|
||||
// in the V86 Opcode Table.
|
||||
//
|
||||
// @param count.
|
||||
// Number of entries to generate.
|
||||
//
|
||||
// @remark None.
|
||||
//
|
||||
.macro INVALID_V86_OPCODE count
|
||||
.rept \count
|
||||
.byte 0
|
||||
.endr
|
||||
.endm
|
||||
|
||||
//
|
||||
// @name GENERATE_PREFIX_HANDLER
|
||||
//
|
||||
// This macro creates a prefix opcode handler.
|
||||
//
|
||||
// @param None.
|
||||
//
|
||||
// @remark None.
|
||||
//
|
||||
.macro GENERATE_PREFIX_HANDLER Name
|
||||
.func Opcode&Name&PrefixV86
|
||||
_Opcode&Name&PrefixV86:
|
||||
or ebx, PREFIX_FLAG_&Name
|
||||
jmp _OpcodeGenericPrefixV86
|
||||
.endfunc
|
||||
.endm
|
||||
|
||||
//
|
||||
// @name INVALID_V86_OPCODE
|
||||
//
|
||||
// This macro prints out visible message and hangs the computer.
|
||||
//
|
||||
// @param None.
|
||||
//
|
||||
// @remark Temporary debugging use.
|
||||
//
|
||||
.macro UNHANDLED_V86_OPCODE
|
||||
/* Print debug message, breakpoint and freeze */
|
||||
push ecx
|
||||
push offset V86DebugMsg
|
||||
call _DbgPrint
|
||||
add esp, 8
|
||||
jmp $
|
||||
.endm
|
||||
|
||||
//
|
||||
// @name TRAP_FIXUPS
|
||||
//
|
||||
|
@ -524,96 +450,6 @@ V86_&Label:
|
|||
2:
|
||||
.endm
|
||||
|
||||
//
|
||||
// @name TRAP_PROLOG
|
||||
//
|
||||
// This macro creates a standard trap entry prologue.
|
||||
// It should be used for entry into any kernel trap (KiTrapXx), but not for
|
||||
// system calls, which require special handling.
|
||||
//
|
||||
// @param Label
|
||||
// Identifying name of the caller function; will be used to append
|
||||
// to the name V86 and DR helper functions, which must already exist.
|
||||
//
|
||||
// @remark Use as follows:
|
||||
// _KiTrap00:
|
||||
// /* Push fake error code */
|
||||
// push 0
|
||||
//
|
||||
// /* Enter common prologue */
|
||||
// TRAP_PROLOG(0)
|
||||
//
|
||||
// /* Handle trap */
|
||||
// <Your Trap Code Here>
|
||||
//
|
||||
.macro TRAP_PROLOG Label EndLabel
|
||||
/* Just to be safe, clear out the HIWORD, since it's reserved */
|
||||
mov word ptr [esp+2], 0
|
||||
|
||||
/* Save the non-volatiles */
|
||||
push ebp
|
||||
push ebx
|
||||
push esi
|
||||
push edi
|
||||
|
||||
/* Save FS and set it to PCR */
|
||||
push fs
|
||||
mov ebx, KGDT_R0_PCR
|
||||
.byte 0x66
|
||||
mov fs, bx
|
||||
|
||||
/* Save exception list and bogus previous mode */
|
||||
push fs:[KPCR_EXCEPTION_LIST]
|
||||
push -1
|
||||
|
||||
/* Save volatiles and segment registers */
|
||||
push eax
|
||||
push ecx
|
||||
push edx
|
||||
push ds
|
||||
push es
|
||||
push gs
|
||||
|
||||
/* Set the R3 data segment */
|
||||
mov ax, KGDT_R3_DATA + RPL_MASK
|
||||
|
||||
/* Skip debug registers and debug stuff */
|
||||
sub esp, 0x30
|
||||
|
||||
/* Load the segment registers */
|
||||
.byte 0x66
|
||||
mov ds, ax
|
||||
.byte 0x66
|
||||
mov es, ax
|
||||
|
||||
/* Check if this interrupt happened in 16-bit mode */
|
||||
cmp esp, 0x10000
|
||||
jb _Ki16BitStackException
|
||||
|
||||
/* Set up frame */
|
||||
mov ebp, esp
|
||||
|
||||
/* Check if this was from V86 Mode */
|
||||
test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
|
||||
jnz V86_&Label
|
||||
|
||||
V86_&EndLabel:
|
||||
/* Get current thread */
|
||||
mov ecx, fs:[KPCR_CURRENT_THREAD]
|
||||
cld
|
||||
|
||||
/* Flush DR7 */
|
||||
and dword ptr [ebp+KTRAP_FRAME_DR7], 0
|
||||
|
||||
/* Check if the thread was being debugged */
|
||||
test byte ptr [ecx+KTHREAD_DEBUG_ACTIVE], 0xFF
|
||||
jnz Dr_&Label
|
||||
|
||||
/* Set the Trap Frame Debug Header */
|
||||
Dr_&EndLabel:
|
||||
SET_TF_DEBUG_HEADER
|
||||
.endm
|
||||
|
||||
//
|
||||
// @name INT_PROLOG
|
||||
//
|
||||
|
@ -898,164 +734,6 @@ Dr_&EndLabel:
|
|||
sti
|
||||
.endm
|
||||
|
||||
//
|
||||
// @name V86_TRAP_PROLOG
|
||||
//
|
||||
// This macro creates a V86 Trap entry prologue.
|
||||
// It should be used for entry into any fast-system call (KiGetTickCount,
|
||||
// KiCallbackReturn, KiRaiseAssertion) and the generic system call handler
|
||||
// (KiSystemService)
|
||||
//
|
||||
// @param Label
|
||||
// Unique label identifying the name of the caller function; will be
|
||||
// used to append to the name of the DR helper function, which must
|
||||
// already exist.
|
||||
//
|
||||
// @remark None.
|
||||
//
|
||||
.macro V86_TRAP_PROLOG Label EndLabel
|
||||
|
||||
/* Skip everything to the error code */
|
||||
sub esp, KTRAP_FRAME_ERROR_CODE
|
||||
|
||||
/* Clear the error code */
|
||||
mov word ptr [esp+KTRAP_FRAME_ERROR_CODE+2], 0
|
||||
|
||||
/* Save the registers we'll trample */
|
||||
mov [esp+KTRAP_FRAME_EBX], ebx
|
||||
mov [esp+KTRAP_FRAME_EAX], eax
|
||||
mov [esp+KTRAP_FRAME_EBP], ebp
|
||||
mov [esp+KTRAP_FRAME_ESI], esi
|
||||
mov [esp+KTRAP_FRAME_EDI], edi
|
||||
|
||||
/* Save PCR and Ring 3 segments */
|
||||
mov ebx, KGDT_R0_PCR
|
||||
mov eax, KGDT_R3_DATA + RPL_MASK
|
||||
|
||||
/* Save ECX and EDX too */
|
||||
mov [esp+KTRAP_FRAME_ECX], ecx
|
||||
mov [esp+KTRAP_FRAME_EDX], edx
|
||||
|
||||
/* Set debugging markers */
|
||||
mov dword ptr [esp+KTRAP_FRAME_PREVIOUS_MODE], -1
|
||||
mov dword ptr [esp+KTRAP_FRAME_DEBUGARGMARK], 0xBADB0D00
|
||||
|
||||
/* Now set segments (use OVERRIDE, 0x66) */
|
||||
.byte 0x66
|
||||
mov fs, bx
|
||||
.byte 0x66
|
||||
mov ds, ax
|
||||
.byte 0x66
|
||||
mov es, ax
|
||||
|
||||
/* Set the trap frame in the stack and clear the direction flag */
|
||||
mov ebp, esp
|
||||
cld
|
||||
|
||||
/* Save the exception list */
|
||||
mov eax, fs:[KPCR_EXCEPTION_LIST]
|
||||
mov [esp+KTRAP_FRAME_EXCEPTION_LIST], eax
|
||||
|
||||
/* Check if we need debugging */
|
||||
mov eax, dr7
|
||||
test eax, ~DR7_RESERVED_MASK
|
||||
mov [esp+KTRAP_FRAME_DR7], eax
|
||||
jnz Dr_&Label
|
||||
|
||||
Dr_&EndLabel:
|
||||
.endm
|
||||
|
||||
//
|
||||
// @name V86_TRAP_EPILOG
|
||||
//
|
||||
// This macro creates an epilogue for leaving V86 traps
|
||||
//
|
||||
// @param None.
|
||||
//
|
||||
// @remark None.
|
||||
//
|
||||
.macro V86_TRAP_EPILOG
|
||||
|
||||
/* Get the current thread and make it unalerted */
|
||||
ExitBegin:
|
||||
mov ebx, PCR[KPCR_CURRENT_THREAD]
|
||||
mov byte ptr [ebx+KTHREAD_ALERTED], 0
|
||||
|
||||
/* Check if it has User-mode APCs pending */
|
||||
cmp byte ptr [ebx+KTHREAD_PENDING_USER_APC], 0
|
||||
jne PendingUserApc
|
||||
|
||||
/* It doesn't, pop the frame */
|
||||
add esp, KTRAP_FRAME_EDX
|
||||
pop edx
|
||||
pop ecx
|
||||
pop eax
|
||||
|
||||
/* Check if DR registers should be restored */
|
||||
test dword ptr [ebp+KTRAP_FRAME_DR7], ~DR7_RESERVED_MASK
|
||||
jnz V86DebugRestore
|
||||
|
||||
/* Finish popping the rest of the frame, and return to P-mode */
|
||||
V86DebugContinue:
|
||||
add esp, 12
|
||||
pop edi
|
||||
pop esi
|
||||
pop ebx
|
||||
pop ebp
|
||||
add esp, 4
|
||||
iretd
|
||||
|
||||
V86DebugRestore:
|
||||
|
||||
/* Get DR0, 1 */
|
||||
xor ebx, ebx
|
||||
mov esi, [ebp+KTRAP_FRAME_DR0]
|
||||
mov edi, [ebp+KTRAP_FRAME_DR1]
|
||||
|
||||
/* Clear DR 7 */
|
||||
mov dr7, ebx
|
||||
|
||||
/* Get DR2 and load DR0-2 */
|
||||
mov ebx, [ebp+KTRAP_FRAME_DR2]
|
||||
mov dr0, esi
|
||||
mov dr1, edi
|
||||
mov dr2, ebx
|
||||
|
||||
/* Get DR3-7 */
|
||||
mov esi, [ebp+KTRAP_FRAME_DR0]
|
||||
mov edi, [ebp+KTRAP_FRAME_DR1]
|
||||
mov ebx, [ebp+KTRAP_FRAME_DR7]
|
||||
|
||||
/* Load them */
|
||||
mov dr3, esi
|
||||
mov dr6, edi
|
||||
mov dr7, ebx
|
||||
jmp V86DebugContinue
|
||||
|
||||
PendingUserApc:
|
||||
|
||||
/* Raise to APC level */
|
||||
mov ecx, APC_LEVEL
|
||||
call @KfRaiseIrql@4
|
||||
|
||||
/* Save KIRQL and deliver APCs */
|
||||
push eax
|
||||
sti
|
||||
push ebp
|
||||
push 0
|
||||
push UserMode
|
||||
call _KiDeliverApc@12
|
||||
|
||||
/* Restore IRQL */
|
||||
pop ecx
|
||||
call @KfLowerIrql@4
|
||||
cli
|
||||
|
||||
/* Check if we're not in V86 anymore */
|
||||
test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
|
||||
jnz ExitBegin
|
||||
.endm
|
||||
|
||||
//
|
||||
// @name TRAP_EPILOG
|
||||
//
|
||||
|
|
|
@ -1050,6 +1050,13 @@ KiSaveProcessorControlState(
|
|||
OUT PKPROCESSOR_STATE ProcessorState
|
||||
);
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
KiSaveProcessorState(
|
||||
IN PKTRAP_FRAME TrapFrame,
|
||||
IN PKEXCEPTION_FRAME ExceptionFrame
|
||||
);
|
||||
|
||||
VOID
|
||||
FASTCALL
|
||||
KiRetireDpcList(
|
||||
|
|
|
@ -944,156 +944,25 @@ KiSaveProcessorState(IN PKTRAP_FRAME TrapFrame,
|
|||
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 **********************************************************/
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
VOID
|
||||
NTAPI
|
||||
KiCoprocessorError(VOID)
|
||||
{
|
||||
PFX_SAVE_AREA NpxArea;
|
||||
|
||||
/* Get the FPU area */
|
||||
NpxArea = KiGetThreadNpxArea(KeGetCurrentThread());
|
||||
|
||||
/* Set CR0_TS */
|
||||
NpxArea->Cr0NpxState = CR0_TS;
|
||||
__writecr0(__readcr0() | CR0_TS);
|
||||
}
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
|
|
|
@ -577,29 +577,6 @@ Error:
|
|||
|
||||
GENERATE_TRAP_HANDLER KiTrap0, 1
|
||||
GENERATE_TRAP_HANDLER KiTrap1, 1
|
||||
|
||||
.func KiTrap2
|
||||
_KiTrap2:
|
||||
//
|
||||
// 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:
|
||||
//
|
||||
// Crash the system
|
||||
//
|
||||
mov eax, EXCEPTION_NMI // STOP fault code
|
||||
jmp _KiSystemFatalException // Bugcheck helper
|
||||
.endfunc
|
||||
|
||||
GENERATE_TRAP_HANDLER KiTrap3, 1
|
||||
GENERATE_TRAP_HANDLER KiTrap4, 1
|
||||
GENERATE_TRAP_HANDLER KiTrap5, 1
|
||||
|
@ -617,61 +594,6 @@ GENERATE_TRAP_HANDLER KiTrap16, 1
|
|||
GENERATE_TRAP_HANDLER KiTrap17, 1
|
||||
GENERATE_TRAP_HANDLER KiTrap19, 1
|
||||
|
||||
.func KiSystemFatalException
|
||||
_KiSystemFatalException:
|
||||
|
||||
/* Push the trap frame */
|
||||
push ebp
|
||||
|
||||
/* Push empty parameters */
|
||||
push 0
|
||||
push 0
|
||||
push 0
|
||||
|
||||
/* Push trap number and bugcheck code */
|
||||
push eax
|
||||
push UNEXPECTED_KERNEL_MODE_TRAP
|
||||
call _KeBugCheckWithTf@24
|
||||
ret
|
||||
.endfunc
|
||||
|
||||
.func KiCoprocessorError@0
|
||||
_KiCoprocessorError@0:
|
||||
|
||||
/* Get the NPX Thread's Initial stack */
|
||||
mov eax, PCR[KPCR_NPX_THREAD]
|
||||
mov eax, [eax+KTHREAD_INITIAL_STACK]
|
||||
|
||||
/* Make space for the FPU Save area */
|
||||
sub eax, SIZEOF_FX_SAVE_AREA
|
||||
|
||||
/* Set the CR0 State */
|
||||
mov dword ptr [eax+FN_CR0_NPX_STATE], 8
|
||||
|
||||
/* Update it */
|
||||
mov eax, cr0
|
||||
or eax, 8
|
||||
mov cr0, eax
|
||||
|
||||
/* Return to caller */
|
||||
ret
|
||||
.endfunc
|
||||
|
||||
.func Ki16BitStackException
|
||||
_Ki16BitStackException:
|
||||
|
||||
/* Save stack */
|
||||
push ss
|
||||
push esp
|
||||
|
||||
/* Go to kernel mode thread stack */
|
||||
mov eax, PCR[KPCR_CURRENT_THREAD]
|
||||
add esp, [eax+KTHREAD_INITIAL_STACK]
|
||||
|
||||
/* Switch to good stack segment */
|
||||
UNHANDLED_PATH "16-Bit Stack"
|
||||
.endfunc
|
||||
|
||||
/* UNEXPECTED INTERRUPT HANDLERS **********************************************/
|
||||
|
||||
.globl _KiStartUnexpectedRange@0
|
||||
|
|
|
@ -551,6 +551,151 @@ KiTrap1Handler(IN PKTRAP_FRAME TrapFrame)
|
|||
TrapFrame);
|
||||
}
|
||||
|
||||
VOID
|
||||
KiTrap2(VOID)
|
||||
{
|
||||
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
|
||||
//
|
||||
__asm__ __volatile__ ("iret\n");
|
||||
}
|
||||
|
||||
//
|
||||
// Unhandled: crash the system
|
||||
//
|
||||
KiSystemFatalException(EXCEPTION_NMI, NULL);
|
||||
}
|
||||
|
||||
VOID
|
||||
FASTCALL
|
||||
KiTrap3Handler(IN PKTRAP_FRAME TrapFrame)
|
||||
|
|
Loading…
Reference in a new issue