mirror of
https://github.com/reactos/reactos.git
synced 2025-02-24 09:25:10 +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
|
.asciz \Reason
|
||||||
.endm
|
.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
|
// @name IDT
|
||||||
//
|
//
|
||||||
|
@ -276,58 +254,6 @@ _HalpHardwareInterrupt&Number:
|
||||||
.endr
|
.endr
|
||||||
.endm
|
.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
|
// @name TRAP_FIXUPS
|
||||||
//
|
//
|
||||||
|
@ -524,96 +450,6 @@ V86_&Label:
|
||||||
2:
|
2:
|
||||||
.endm
|
.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
|
// @name INT_PROLOG
|
||||||
//
|
//
|
||||||
|
@ -898,164 +734,6 @@ Dr_&EndLabel:
|
||||||
sti
|
sti
|
||||||
.endm
|
.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
|
// @name TRAP_EPILOG
|
||||||
//
|
//
|
||||||
|
|
|
@ -1050,6 +1050,13 @@ KiSaveProcessorControlState(
|
||||||
OUT PKPROCESSOR_STATE ProcessorState
|
OUT PKPROCESSOR_STATE ProcessorState
|
||||||
);
|
);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
KiSaveProcessorState(
|
||||||
|
IN PKTRAP_FRAME TrapFrame,
|
||||||
|
IN PKEXCEPTION_FRAME ExceptionFrame
|
||||||
|
);
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
FASTCALL
|
FASTCALL
|
||||||
KiRetireDpcList(
|
KiRetireDpcList(
|
||||||
|
|
|
@ -944,156 +944,25 @@ KiSaveProcessorState(IN PKTRAP_FRAME TrapFrame,
|
||||||
KiSaveProcessorControlState(&Prcb->ProcessorState);
|
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 **********************************************************/
|
/* 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
|
* @implemented
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -577,29 +577,6 @@ Error:
|
||||||
|
|
||||||
GENERATE_TRAP_HANDLER KiTrap0, 1
|
GENERATE_TRAP_HANDLER KiTrap0, 1
|
||||||
GENERATE_TRAP_HANDLER KiTrap1, 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 KiTrap3, 1
|
||||||
GENERATE_TRAP_HANDLER KiTrap4, 1
|
GENERATE_TRAP_HANDLER KiTrap4, 1
|
||||||
GENERATE_TRAP_HANDLER KiTrap5, 1
|
GENERATE_TRAP_HANDLER KiTrap5, 1
|
||||||
|
@ -617,61 +594,6 @@ GENERATE_TRAP_HANDLER KiTrap16, 1
|
||||||
GENERATE_TRAP_HANDLER KiTrap17, 1
|
GENERATE_TRAP_HANDLER KiTrap17, 1
|
||||||
GENERATE_TRAP_HANDLER KiTrap19, 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 **********************************************/
|
/* UNEXPECTED INTERRUPT HANDLERS **********************************************/
|
||||||
|
|
||||||
.globl _KiStartUnexpectedRange@0
|
.globl _KiStartUnexpectedRange@0
|
||||||
|
|
|
@ -551,6 +551,151 @@ KiTrap1Handler(IN PKTRAP_FRAME TrapFrame)
|
||||||
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
|
VOID
|
||||||
FASTCALL
|
FASTCALL
|
||||||
KiTrap3Handler(IN PKTRAP_FRAME TrapFrame)
|
KiTrap3Handler(IN PKTRAP_FRAME TrapFrame)
|
||||||
|
|
Loading…
Reference in a new issue