mirror of
https://github.com/ApfelTeeSaft/reactos.git
synced 2026-09-03 04:13:31 +00:00
Trap handlers in C patch 6 of X:
[NTOS]: Implement Trap 7 and 16 in C. These are the last two FPU/NPX traps. Not really good with x86 FPU stuff, so there might be some mistakes to look over later.
[NTOS]: Fixed a bug in Trap 19 handler (forgot to write CR0 back).
svn path=/trunk/; revision=45014
This commit is contained in:
@@ -27,7 +27,21 @@ Ke386SaveFpuState(IN PFX_SAVE_AREA SaveArea)
|
||||
{
|
||||
__asm__ __volatile__ ("fnsave %0\n wait\n" : : "m"(SaveArea));
|
||||
}
|
||||
}
|
||||
|
||||
FORCEINLINE
|
||||
VOID
|
||||
Ke386LoadFpuState(IN PFX_SAVE_AREA SaveArea)
|
||||
{
|
||||
extern ULONG KeI386FxsrPresent;
|
||||
if (KeI386FxsrPresent)
|
||||
{
|
||||
__asm__ __volatile__ ("fxrstor %0\n" : "=m"(SaveArea) : );
|
||||
}
|
||||
else
|
||||
{
|
||||
__asm__ __volatile__ (".globl _FrRestore\n _FrRestore: \n frstor %0\n wait\n" : "=m"(SaveArea) : );
|
||||
}
|
||||
}
|
||||
|
||||
FORCEINLINE
|
||||
|
||||
@@ -137,6 +137,13 @@ KiVdmTrap(IN PKTRAP_FRAME TrapFrame)
|
||||
((KiUserTrap(TrapFrame)) && (PsGetCurrentProcess()->VdmObjects)));
|
||||
}
|
||||
|
||||
PFX_SAVE_AREA
|
||||
FORCEINLINE
|
||||
KiGetThreadNpxArea(IN PKTHREAD Thread)
|
||||
{
|
||||
return (PFX_SAVE_AREA)((ULONG_PTR)Thread->InitialStack - sizeof(FX_SAVE_AREA));
|
||||
}
|
||||
|
||||
VOID
|
||||
FORCEINLINE
|
||||
KiTrapFrameFromPushaStack(IN PKTRAP_FRAME TrapFrame)
|
||||
|
||||
@@ -693,317 +693,7 @@ GENERATE_TRAP_HANDLER KiTrap3, 1
|
||||
GENERATE_TRAP_HANDLER KiTrap4, 1
|
||||
GENERATE_TRAP_HANDLER KiTrap5, 1
|
||||
GENERATE_TRAP_HANDLER KiTrap6, 1
|
||||
|
||||
.func KiTrap7
|
||||
TRAP_FIXUPS kit7_a, kit7_t, DoFixupV86, DoNotFixupAbios
|
||||
_KiTrap7:
|
||||
/* Push error code */
|
||||
push 0
|
||||
|
||||
/* Enter trap */
|
||||
TRAP_PROLOG kit7_a, kit7_t
|
||||
|
||||
/* Get the current thread and stack */
|
||||
StartTrapHandle:
|
||||
mov eax, PCR[KPCR_CURRENT_THREAD]
|
||||
mov ecx, [eax+KTHREAD_INITIAL_STACK]
|
||||
sub ecx, NPX_FRAME_LENGTH
|
||||
|
||||
/* Check if emulation is enabled */
|
||||
test byte ptr [ecx+FN_CR0_NPX_STATE], CR0_EM
|
||||
jnz EmulationEnabled
|
||||
|
||||
CheckState:
|
||||
/* Check if the NPX state is loaded */
|
||||
cmp byte ptr [eax+KTHREAD_NPX_STATE], NPX_STATE_LOADED
|
||||
mov ebx, cr0
|
||||
jz IsLoaded
|
||||
|
||||
/* Remove flags */
|
||||
and ebx, ~(CR0_MP + CR0_TS + CR0_EM)
|
||||
mov cr0, ebx
|
||||
|
||||
/* Check the NPX thread */
|
||||
mov edx, PCR[KPCR_NPX_THREAD]
|
||||
or edx, edx
|
||||
jz NoNpxThread
|
||||
|
||||
/* Get the NPX Stack */
|
||||
mov esi, [edx+KTHREAD_INITIAL_STACK]
|
||||
sub esi, NPX_FRAME_LENGTH
|
||||
|
||||
/* Check if we have FXSR and check which operand to use */
|
||||
test byte ptr _KeI386FxsrPresent, 1
|
||||
jz FnSave
|
||||
fxsave [esi]
|
||||
jmp AfterSave
|
||||
|
||||
FnSave:
|
||||
fnsave [esi]
|
||||
|
||||
AfterSave:
|
||||
/* Set the thread's state to dirty */
|
||||
mov byte ptr [edx+KTHREAD_NPX_STATE], NPX_STATE_NOT_LOADED
|
||||
|
||||
NoNpxThread:
|
||||
/* Check if we have FXSR and choose which operand to use */
|
||||
test byte ptr _KeI386FxsrPresent, 1
|
||||
jz FrRestore
|
||||
fxrstor [ecx]
|
||||
jmp AfterRestore
|
||||
|
||||
FrRestore:
|
||||
frstor [ecx]
|
||||
|
||||
AfterRestore:
|
||||
/* Set state loaded */
|
||||
mov byte ptr [eax+KTHREAD_NPX_STATE], NPX_STATE_LOADED
|
||||
mov PCR[KPCR_NPX_THREAD], eax
|
||||
|
||||
/* Enable interrupts to happen now */
|
||||
sti
|
||||
nop
|
||||
|
||||
/* Check if CR0 needs to be reloaded due to a context switch */
|
||||
cmp dword ptr [ecx+FN_CR0_NPX_STATE], 0
|
||||
jz _Kei386EoiHelper@0
|
||||
|
||||
/* We have to reload CR0... disable interrupts */
|
||||
cli
|
||||
|
||||
/* Get CR0 and update it */
|
||||
mov ebx, cr0
|
||||
or ebx, [ecx+FN_CR0_NPX_STATE]
|
||||
mov cr0, ebx
|
||||
|
||||
/* Restore interrupts and check if TS is back on */
|
||||
sti
|
||||
test bl, CR0_TS
|
||||
jz _Kei386EoiHelper@0
|
||||
|
||||
/* Clear TS, and loop handling again */
|
||||
clts
|
||||
cli
|
||||
jmp StartTrapHandle
|
||||
|
||||
KernelNpx:
|
||||
|
||||
/* Set delayed error */
|
||||
or dword ptr [ecx+FN_CR0_NPX_STATE], CR0_TS
|
||||
|
||||
/* Check if this happened during restore */
|
||||
cmp dword ptr [ebp+KTRAP_FRAME_EIP], offset FrRestore
|
||||
jnz UserNpx
|
||||
|
||||
/* Skip instruction and dispatch the exception */
|
||||
add dword ptr [ebp+KTRAP_FRAME_EIP], 3
|
||||
jmp _Kei386EoiHelper@0
|
||||
|
||||
IsLoaded:
|
||||
/* Check if TS is set */
|
||||
test bl, CR0_TS
|
||||
jnz TsSetOnLoadedState
|
||||
|
||||
HandleNpxFault:
|
||||
/* Check if the trap came from V86 mode */
|
||||
test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
|
||||
jnz V86Npx
|
||||
|
||||
/* Check if it came from kernel mode */
|
||||
test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
|
||||
jz KernelNpx
|
||||
|
||||
/* Check if it came from a VDM */
|
||||
cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
|
||||
jne V86Npx
|
||||
|
||||
UserNpx:
|
||||
/* Get the current thread */
|
||||
mov eax, PCR[KPCR_CURRENT_THREAD]
|
||||
|
||||
/* Check NPX state */
|
||||
cmp byte ptr [eax+KTHREAD_NPX_STATE], NPX_STATE_NOT_LOADED
|
||||
|
||||
/* Get the NPX save area */
|
||||
mov ecx, [eax+KTHREAD_INITIAL_STACK]
|
||||
lea ecx, [ecx-NPX_FRAME_LENGTH]
|
||||
jz NoSaveRestore
|
||||
|
||||
HandleUserNpx:
|
||||
|
||||
/* Set new CR0 */
|
||||
mov ebx, cr0
|
||||
and ebx, ~(CR0_MP + CR0_EM + CR0_TS)
|
||||
mov cr0, ebx
|
||||
|
||||
/* Check if we have FX support */
|
||||
test byte ptr _KeI386FxsrPresent, 1
|
||||
jz FnSave2
|
||||
|
||||
/* Save the state */
|
||||
fxsave [ecx]
|
||||
jmp MakeCr0Dirty
|
||||
FnSave2:
|
||||
fnsave [ecx]
|
||||
wait
|
||||
|
||||
MakeCr0Dirty:
|
||||
/* Make CR0 state not loaded */
|
||||
or ebx, NPX_STATE_NOT_LOADED
|
||||
or ebx, [ecx+FN_CR0_NPX_STATE]
|
||||
mov cr0, ebx
|
||||
|
||||
/* Update NPX state */
|
||||
mov byte ptr [eax+KTHREAD_NPX_STATE], NPX_STATE_NOT_LOADED
|
||||
mov dword ptr PCR[KPCR_NPX_THREAD], 0
|
||||
|
||||
NoSaveRestore:
|
||||
/* Clear the TS bit and re-enable interrupts */
|
||||
and dword ptr [ecx+FN_CR0_NPX_STATE], ~CR0_TS
|
||||
sti
|
||||
|
||||
/* Check if we have FX support */
|
||||
test byte ptr _KeI386FxsrPresent, 1
|
||||
jz FnError
|
||||
|
||||
/* Get error offset, control and status words */
|
||||
mov ebx, [ecx+FX_ERROR_OFFSET]
|
||||
movzx eax, word ptr [ecx+FX_CONTROL_WORD]
|
||||
movzx edx, word ptr [ecx+FX_STATUS_WORD]
|
||||
|
||||
/* Get the faulting opcode */
|
||||
mov esi, [ecx+FX_DATA_OFFSET]
|
||||
jmp CheckError
|
||||
|
||||
FnError:
|
||||
/* Get error offset, control and status words */
|
||||
mov ebx, [ecx+FP_ERROR_OFFSET]
|
||||
movzx eax, word ptr [ecx+FP_CONTROL_WORD]
|
||||
movzx edx, word ptr [ecx+FP_STATUS_WORD]
|
||||
|
||||
/* Get the faulting opcode */
|
||||
mov esi, [ecx+FP_DATA_OFFSET]
|
||||
|
||||
CheckError:
|
||||
/* Mask exceptions */
|
||||
and eax, 0x3F
|
||||
not eax
|
||||
and eax, edx
|
||||
|
||||
/* Check if what's left is invalid */
|
||||
test al, 1
|
||||
jz ValidNpxOpcode
|
||||
|
||||
/* Check if it was a stack fault */
|
||||
test al, 64
|
||||
jnz InvalidStack
|
||||
|
||||
/* Raise exception */
|
||||
mov eax, STATUS_FLOAT_INVALID_OPERATION
|
||||
jmp _DispatchOneParamZero
|
||||
|
||||
InvalidStack:
|
||||
|
||||
/* Raise exception */
|
||||
mov eax, STATUS_FLOAT_STACK_CHECK
|
||||
jmp _DispatchTwoParamZero
|
||||
|
||||
ValidNpxOpcode:
|
||||
|
||||
/* Check for divide by 0 */
|
||||
test al, 4
|
||||
jz 1f
|
||||
|
||||
/* Raise exception */
|
||||
mov eax, STATUS_FLOAT_DIVIDE_BY_ZERO
|
||||
jmp _DispatchOneParamZero
|
||||
|
||||
1:
|
||||
/* Check for denormal */
|
||||
test al, 2
|
||||
jz 1f
|
||||
|
||||
/* Raise exception */
|
||||
mov eax, STATUS_FLOAT_INVALID_OPERATION
|
||||
jmp _DispatchOneParamZero
|
||||
|
||||
1:
|
||||
/* Check for overflow */
|
||||
test al, 8
|
||||
jz 1f
|
||||
|
||||
/* Raise exception */
|
||||
mov eax, STATUS_FLOAT_OVERFLOW
|
||||
jmp _DispatchOneParamZero
|
||||
|
||||
1:
|
||||
/* Check for underflow */
|
||||
test al, 16
|
||||
jz 1f
|
||||
|
||||
/* Raise exception */
|
||||
mov eax, STATUS_FLOAT_UNDERFLOW
|
||||
jmp _DispatchOneParamZero
|
||||
|
||||
1:
|
||||
/* Check for precision fault */
|
||||
test al, 32
|
||||
jz UnexpectedNpx
|
||||
|
||||
/* Raise exception */
|
||||
mov eax, STATUS_FLOAT_INEXACT_RESULT
|
||||
jmp _DispatchOneParamZero
|
||||
|
||||
UnexpectedNpx:
|
||||
|
||||
/* Strange result, bugcheck the OS */
|
||||
sti
|
||||
push ebp
|
||||
push 0
|
||||
push 0
|
||||
push eax
|
||||
push 1
|
||||
push TRAP_CAUSE_UNKNOWN
|
||||
call _KeBugCheckWithTf@24
|
||||
|
||||
V86Npx:
|
||||
/* Check if this is a VDM */
|
||||
mov eax, PCR[KPCR_CURRENT_THREAD]
|
||||
mov ebx, [eax+KTHREAD_APCSTATE_PROCESS]
|
||||
cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
|
||||
jz HandleUserNpx
|
||||
|
||||
/* V86 NPX not handled */
|
||||
UNHANDLED_V86_PATH
|
||||
|
||||
EmulationEnabled:
|
||||
/* Did this come from kernel-mode? */
|
||||
cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R0_CODE
|
||||
jz CheckState
|
||||
|
||||
/* It came from user-mode, so this would only be valid inside a VDM */
|
||||
/* Since we don't actually have VDMs in ROS, bugcheck. */
|
||||
jmp UnexpectedNpx
|
||||
|
||||
TsSetOnLoadedState:
|
||||
/* TS shouldn't be set, unless this we don't have a Math Processor */
|
||||
test bl, CR0_MP
|
||||
jnz BogusTrap
|
||||
|
||||
/* Strange that we got a trap at all, but ignore and continue */
|
||||
clts
|
||||
jmp _Kei386EoiHelper@0
|
||||
|
||||
BogusTrap:
|
||||
/* Cause a bugcheck */
|
||||
push 0
|
||||
push 0
|
||||
push ebx
|
||||
push 2
|
||||
push TRAP_CAUSE_UNKNOWN
|
||||
call _KeBugCheckEx@20
|
||||
.endfunc
|
||||
|
||||
GENERATE_TRAP_HANDLER KiTrap7, 1
|
||||
GENERATE_TRAP_HANDLER KiTrap8, 0
|
||||
GENERATE_TRAP_HANDLER KiTrap9, 1
|
||||
GENERATE_TRAP_HANDLER KiTrap10, 0
|
||||
@@ -1496,33 +1186,7 @@ DispatchV86Gpf:
|
||||
|
||||
GENERATE_TRAP_HANDLER KiTrap14, 0
|
||||
GENERATE_TRAP_HANDLER KiTrap0F, 1
|
||||
|
||||
.func KiTrap16
|
||||
TRAP_FIXUPS kit10_a, kit10_t, DoFixupV86, DoNotFixupAbios
|
||||
_KiTrap16:
|
||||
/* Push error code */
|
||||
push 0
|
||||
|
||||
/* Enter trap */
|
||||
TRAP_PROLOG kit10_a, kit10_t
|
||||
|
||||
/* Check if this is the NPX Thread */
|
||||
mov eax, PCR[KPCR_CURRENT_THREAD]
|
||||
cmp eax, PCR[KPCR_NPX_THREAD]
|
||||
|
||||
/* Get the initial stack and NPX frame */
|
||||
mov ecx, [eax+KTHREAD_INITIAL_STACK]
|
||||
lea ecx, [ecx-NPX_FRAME_LENGTH]
|
||||
|
||||
/* If this is a valid fault, handle it */
|
||||
jz HandleNpxFault
|
||||
|
||||
/* Otherwise, re-enable interrupts and set delayed error */
|
||||
sti
|
||||
or dword ptr [ecx+FN_CR0_NPX_STATE], CR0_TS
|
||||
jmp _Kei386EoiHelper@0
|
||||
.endfunc
|
||||
|
||||
GENERATE_TRAP_HANDLER KiTrap16, 1
|
||||
GENERATE_TRAP_HANDLER KiTrap17, 1
|
||||
GENERATE_TRAP_HANDLER KiTrap19, 1
|
||||
|
||||
|
||||
@@ -251,6 +251,163 @@ KiDebugHandler(IN PKTRAP_FRAME TrapFrame,
|
||||
TrapFrame);
|
||||
}
|
||||
|
||||
VOID
|
||||
FASTCALL
|
||||
KiNpxHandler(IN PKTRAP_FRAME TrapFrame,
|
||||
IN PKTHREAD Thread,
|
||||
IN PFX_SAVE_AREA SaveArea)
|
||||
{
|
||||
ULONG Cr0, Mask, Error, ErrorOffset, DataOffset;
|
||||
extern VOID FrRestore(VOID);
|
||||
|
||||
/* Check for VDM trap */
|
||||
ASSERT((KiVdmTrap(TrapFrame)) == FALSE);
|
||||
|
||||
/* Check for kernel trap */
|
||||
if (!KiUserTrap(TrapFrame))
|
||||
{
|
||||
/* Kernel might've tripped a delayed error */
|
||||
SaveArea->Cr0NpxState |= CR0_TS;
|
||||
|
||||
/* Only valid if it happened during a restore */
|
||||
if ((PVOID)TrapFrame->Eip == FrRestore)
|
||||
{
|
||||
/* It did, so just skip the instruction */
|
||||
TrapFrame->Eip += 3; /* sizeof(FRSTOR) */
|
||||
KiEoiHelper(TrapFrame);
|
||||
}
|
||||
}
|
||||
|
||||
/* User or kernel trap -- get ready to issue an exception */
|
||||
if (Thread->NpxState == NPX_STATE_NOT_LOADED)
|
||||
{
|
||||
/* Update CR0 */
|
||||
Cr0 = __readcr0();
|
||||
Cr0 &= ~(CR0_MP | CR0_EM | CR0_TS);
|
||||
__writecr0(Cr0);
|
||||
|
||||
/* Save FPU state */
|
||||
Ke386SaveFpuState(SaveArea);
|
||||
|
||||
/* Mark CR0 state dirty */
|
||||
Cr0 |= NPX_STATE_NOT_LOADED;
|
||||
Cr0 |= SaveArea->Cr0NpxState;
|
||||
__writecr0(Cr0);
|
||||
|
||||
/* Update NPX state */
|
||||
Thread->NpxState = NPX_STATE_NOT_LOADED;
|
||||
KeGetCurrentPrcb()->NpxThread = NULL;
|
||||
}
|
||||
|
||||
/* Clear the TS bit and re-enable interrupts */
|
||||
SaveArea->Cr0NpxState &= ~CR0_TS;
|
||||
_enable();
|
||||
|
||||
/* Check if we should get the FN or FX error */
|
||||
if (KeI386FxsrPresent)
|
||||
{
|
||||
/* Get it from FX */
|
||||
Mask = SaveArea->U.FxArea.ControlWord;
|
||||
Error = SaveArea->U.FxArea.StatusWord;
|
||||
|
||||
/* Get the FPU exception address too */
|
||||
ErrorOffset = SaveArea->U.FxArea.ErrorOffset;
|
||||
DataOffset = SaveArea->U.FxArea.DataOffset;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Get it from FN */
|
||||
Mask = SaveArea->U.FnArea.ControlWord;
|
||||
Error = SaveArea->U.FnArea.StatusWord;
|
||||
|
||||
/* Get the FPU exception address too */
|
||||
ErrorOffset = SaveArea->U.FnArea.ErrorOffset;
|
||||
DataOffset = SaveArea->U.FnArea.DataOffset;
|
||||
}
|
||||
|
||||
/* Get legal exceptions that software should handle */
|
||||
Error &= (FSW_INVALID_OPERATION |
|
||||
FSW_DENORMAL |
|
||||
FSW_ZERO_DIVIDE |
|
||||
FSW_OVERFLOW |
|
||||
FSW_UNDERFLOW |
|
||||
FSW_PRECISION);
|
||||
Error &= ~Mask;
|
||||
|
||||
if (Error & FSW_STACK_FAULT)
|
||||
{
|
||||
/* Issue stack check fault */
|
||||
KiDispatchException2Args(STATUS_FLOAT_STACK_CHECK,
|
||||
ErrorOffset,
|
||||
0,
|
||||
DataOffset,
|
||||
TrapFrame);
|
||||
}
|
||||
|
||||
/* Check for invalid operation */
|
||||
if (Error & FSW_INVALID_OPERATION)
|
||||
{
|
||||
/* Issue fault */
|
||||
KiDispatchException1Args(STATUS_FLOAT_INVALID_OPERATION,
|
||||
ErrorOffset,
|
||||
0,
|
||||
TrapFrame);
|
||||
}
|
||||
|
||||
/* Check for divide by zero */
|
||||
if (Error & FSW_ZERO_DIVIDE)
|
||||
{
|
||||
/* Issue fault */
|
||||
KiDispatchException1Args(STATUS_FLOAT_DIVIDE_BY_ZERO,
|
||||
ErrorOffset,
|
||||
0,
|
||||
TrapFrame);
|
||||
}
|
||||
|
||||
/* Check for denormal */
|
||||
if (Error & FSW_DENORMAL)
|
||||
{
|
||||
/* Issue fault */
|
||||
KiDispatchException1Args(STATUS_FLOAT_INVALID_OPERATION,
|
||||
ErrorOffset,
|
||||
0,
|
||||
TrapFrame);
|
||||
}
|
||||
|
||||
/* Check for overflow */
|
||||
if (Error & FSW_OVERFLOW)
|
||||
{
|
||||
/* Issue fault */
|
||||
KiDispatchException1Args(STATUS_FLOAT_OVERFLOW,
|
||||
ErrorOffset,
|
||||
0,
|
||||
TrapFrame);
|
||||
}
|
||||
|
||||
/* Check for underflow */
|
||||
if (Error & FSW_UNDERFLOW)
|
||||
{
|
||||
/* Issue fault */
|
||||
KiDispatchException1Args(STATUS_FLOAT_UNDERFLOW,
|
||||
ErrorOffset,
|
||||
0,
|
||||
TrapFrame);
|
||||
}
|
||||
|
||||
/* Check for precision fault */
|
||||
if (Error & FSW_PRECISION)
|
||||
{
|
||||
/* Issue fault */
|
||||
KiDispatchException1Args(STATUS_FLOAT_INEXACT_RESULT,
|
||||
ErrorOffset,
|
||||
0,
|
||||
TrapFrame);
|
||||
}
|
||||
|
||||
/* Unknown FPU fault */
|
||||
KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 1, Error, 0, 0, TrapFrame);
|
||||
}
|
||||
|
||||
VOID
|
||||
FASTCALL
|
||||
KiTrap0Handler(IN PKTRAP_FRAME TrapFrame)
|
||||
@@ -387,6 +544,115 @@ KiTrap6Handler(IN PKTRAP_FRAME TrapFrame)
|
||||
|
||||
}
|
||||
|
||||
VOID
|
||||
FASTCALL
|
||||
KiTrap7Handler(IN PKTRAP_FRAME TrapFrame)
|
||||
{
|
||||
PKTHREAD Thread, NpxThread;
|
||||
PFX_SAVE_AREA SaveArea, NpxSaveArea;
|
||||
ULONG Cr0;
|
||||
|
||||
/* Save trap frame */
|
||||
KiEnterTrap(TrapFrame);
|
||||
|
||||
/* Try to handle NPX delay load */
|
||||
while (TRUE)
|
||||
{
|
||||
/* Get the current thread */
|
||||
Thread = KeGetCurrentThread();
|
||||
|
||||
/* Get the NPX frame */
|
||||
SaveArea = KiGetThreadNpxArea(Thread);
|
||||
|
||||
/* Check if emulation is enabled */
|
||||
if (SaveArea->Cr0NpxState & CR0_EM)
|
||||
{
|
||||
/* Not implemented */
|
||||
UNIMPLEMENTED;
|
||||
while (TRUE);
|
||||
}
|
||||
|
||||
/* Save CR0 and check NPX state */
|
||||
Cr0 = __readcr0();
|
||||
if (Thread->NpxState != NPX_STATE_LOADED)
|
||||
{
|
||||
/* Update CR0 */
|
||||
Cr0 &= ~(CR0_MP | CR0_EM | CR0_TS);
|
||||
__writecr0(Cr0);
|
||||
|
||||
/* Get the NPX thread */
|
||||
NpxThread = KeGetCurrentPrcb()->NpxThread;
|
||||
if (NpxThread)
|
||||
{
|
||||
/* Get the NPX frame */
|
||||
NpxSaveArea = KiGetThreadNpxArea(NpxThread);
|
||||
|
||||
/* Save FPU state */
|
||||
Ke386SaveFpuState(NpxSaveArea);
|
||||
|
||||
/* Update NPX state */
|
||||
Thread->NpxState = NPX_STATE_NOT_LOADED;
|
||||
}
|
||||
|
||||
/* Load FPU state */
|
||||
Ke386LoadFpuState(SaveArea);
|
||||
|
||||
/* Update NPX state */
|
||||
Thread->NpxState = NPX_STATE_LOADED;
|
||||
KeGetCurrentPrcb()->NpxThread = Thread;
|
||||
|
||||
/* Enable interrupts */
|
||||
_enable();
|
||||
|
||||
/* Check if CR0 needs to be reloaded due to context switch */
|
||||
if (!SaveArea->Cr0NpxState) KiEoiHelper(TrapFrame);
|
||||
|
||||
/* Otherwise, we need to reload CR0, disable interrupts */
|
||||
_disable();
|
||||
|
||||
/* Reload CR0 */
|
||||
Cr0 = __readcr0();
|
||||
Cr0 |= SaveArea->Cr0NpxState;
|
||||
__writecr0(Cr0);
|
||||
|
||||
/* Now restore interrupts and check for TS */
|
||||
_enable();
|
||||
if (Cr0 & CR0_TS) KiEoiHelper(TrapFrame);
|
||||
|
||||
/* We're still here -- clear TS and try again */
|
||||
__writecr0(__readcr0() &~ CR0_TS);
|
||||
_disable();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This is an actual fault, not a lack of FPU state */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* TS should not be set */
|
||||
if (Cr0 & CR0_TS)
|
||||
{
|
||||
/*
|
||||
* If it's incorrectly set, then maybe the state is actually still valid
|
||||
* but we could've lock track of that due to a BIOS call.
|
||||
* Make sure MP is still set, which should verify the theory.
|
||||
*/
|
||||
if (Cr0 & CR0_MP)
|
||||
{
|
||||
/* Indeed, the state is actually still valid, so clear TS */
|
||||
__writecr0(__readcr0() &~ CR0_TS);
|
||||
KiEoiHelper(TrapFrame);
|
||||
}
|
||||
|
||||
/* Otherwise, something strange is going on */
|
||||
KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 2, Cr0, 0, 0, TrapFrame);
|
||||
}
|
||||
|
||||
/* It's not a delayed load, so process this trap as an NPX fault */
|
||||
KiNpxHandler(TrapFrame, Thread, SaveArea);
|
||||
}
|
||||
|
||||
VOID
|
||||
FASTCALL
|
||||
KiTrap8Handler(IN PKTRAP_FRAME TrapFrame)
|
||||
@@ -581,6 +847,34 @@ KiTrap0FHandler(IN PKTRAP_FRAME TrapFrame)
|
||||
KiSystemFatalException(EXCEPTION_RESERVED_TRAP, TrapFrame);
|
||||
}
|
||||
|
||||
|
||||
VOID
|
||||
FASTCALL
|
||||
KiTrap16Handler(IN PKTRAP_FRAME TrapFrame)
|
||||
{
|
||||
PKTHREAD Thread;
|
||||
PFX_SAVE_AREA SaveArea;
|
||||
|
||||
/* Save trap frame */
|
||||
KiEnterTrap(TrapFrame);
|
||||
|
||||
/* Check if this is the NPX thrad */
|
||||
Thread = KeGetCurrentThread();
|
||||
SaveArea = KiGetThreadNpxArea(Thread);
|
||||
if (Thread != KeGetCurrentPrcb()->NpxThread)
|
||||
{
|
||||
/* It isn't, enable interrupts and set delayed error */
|
||||
_enable();
|
||||
SaveArea->Cr0NpxState |= CR0_TS;
|
||||
|
||||
/* End trap */
|
||||
KiEoiHelper(TrapFrame);
|
||||
}
|
||||
|
||||
/* Otherwise, proceed with NPX fault handling */
|
||||
KiNpxHandler(TrapFrame, Thread, SaveArea);
|
||||
}
|
||||
|
||||
VOID
|
||||
FASTCALL
|
||||
KiTrap17Handler(IN PKTRAP_FRAME TrapFrame)
|
||||
@@ -613,7 +907,7 @@ KiTrap19Handler(IN PKTRAP_FRAME TrapFrame)
|
||||
}
|
||||
|
||||
/* Get the NPX frame */
|
||||
SaveArea = (PFX_SAVE_AREA)((ULONG_PTR)Thread->InitialStack - sizeof(FX_SAVE_AREA));
|
||||
SaveArea = KiGetThreadNpxArea(Thread);
|
||||
|
||||
/* Check for VDM trap */
|
||||
ASSERT((KiVdmTrap(TrapFrame)) == FALSE);
|
||||
@@ -636,6 +930,7 @@ KiTrap19Handler(IN PKTRAP_FRAME TrapFrame)
|
||||
/* Mark CR0 state dirty */
|
||||
Cr0 |= NPX_STATE_NOT_LOADED;
|
||||
Cr0 |= SaveArea->Cr0NpxState;
|
||||
__writecr0(Cr0);
|
||||
|
||||
/* Update NPX state */
|
||||
Thread->NpxState = NPX_STATE_NOT_LOADED;
|
||||
|
||||
Reference in New Issue
Block a user