fpu.c
来自「一个类似windows」· C语言 代码 · 共 605 行 · 第 1/2 页
C
605 行
asm volatile("fxsave %0" : : "m"(FxSaveArea->U.FxArea));
MxcsrFeatureMask = FxSaveArea->U.FxArea.MXCsrMask;
if (MxcsrFeatureMask == 0)
{
MxcsrFeatureMask = 0x0000ffbf;
}
}
/* FIXME: Check for SSE3 in Ke386CpuidFlags2! */
if (Prcb->FeatureBits & (X86_FEATURE_SSE | X86_FEATURE_SSE2))
{
Ke386SetCr4(Ke386GetCr4() | X86_CR4_OSXMMEXCPT);
/* enable SSE */
KeI386XMMIPresent = 1;
}
Ke386SetCr0(Ke386GetCr0() | X86_CR0_TS);
Ke386RestoreFlags(Flags);
}
PFX_SAVE_AREA
KiGetFpuState(PKTHREAD Thread)
{
PFX_SAVE_AREA FxSaveArea = NULL;
KIRQL OldIrql;
ULONG Cr0;
KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
if (Thread->NpxState & NPX_STATE_VALID)
{
FxSaveArea = (PFX_SAVE_AREA)((ULONG_PTR)Thread->InitialStack - sizeof (FX_SAVE_AREA));
if (Thread->NpxState & NPX_STATE_DIRTY)
{
ASSERT(KeGetCurrentPrcb()->NpxThread == Thread);
Cr0 = Ke386GetCr0();
asm volatile("clts");
if (KeI386FxsrPresent)
asm volatile("fxsave %0" : : "m"(FxSaveArea->U.FxArea));
else
{
asm volatile("fnsave %0" : : "m"(FxSaveArea->U.FnArea));
/* FPU state has to be reloaded because fnsave changes it. */
Cr0 |= X86_CR0_TS;
KeGetCurrentPrcb()->NpxThread = NULL;
}
Ke386SetCr0(Cr0);
Thread->NpxState = NPX_STATE_VALID;
}
}
KeLowerIrql(OldIrql);
return FxSaveArea;
}
NTSTATUS
KiHandleFpuFault(PKTRAP_FRAME Tf, ULONG ExceptionNr)
{
if (ExceptionNr == 7) /* device not present */
{
BOOL FpuInitialized = FALSE;
unsigned int cr0 = Ke386GetCr0();
PKTHREAD CurrentThread;
PFX_SAVE_AREA FxSaveArea;
KIRQL oldIrql;
#ifndef CONFIG_SMP
PKTHREAD NpxThread;
#endif
(void) cr0;
ASSERT((cr0 & X86_CR0_TS) == X86_CR0_TS);
ASSERT((Tf->EFlags & X86_EFLAGS_VM) == 0);
ASSERT((cr0 & X86_CR0_EM) == 0);
/* disable scheduler, clear TS in cr0 */
ASSERT_IRQL(DISPATCH_LEVEL);
KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);
asm volatile("clts");
CurrentThread = KeGetCurrentThread();
#ifndef CONFIG_SMP
NpxThread = KeGetCurrentPrcb()->NpxThread;
#endif
ASSERT(CurrentThread != NULL);
DPRINT("Device not present exception happened! (Cr0 = 0x%x, NpxState = 0x%x)\n", cr0, CurrentThread->NpxState);
#ifndef CONFIG_SMP
/* check if the current thread already owns the FPU */
if (NpxThread != CurrentThread) /* FIXME: maybe this could be an assertation */
{
/* save the FPU state into the owner's save area */
if (NpxThread != NULL)
{
KeGetCurrentPrcb()->NpxThread = NULL;
FxSaveArea = (PFX_SAVE_AREA)((ULONG_PTR)NpxThread->InitialStack - sizeof (FX_SAVE_AREA));
/* the fnsave might raise a delayed #MF exception */
if (KeI386FxsrPresent)
{
asm volatile("fxsave %0" : : "m"(FxSaveArea->U.FxArea));
}
else
{
asm volatile("fnsave %0" : : "m"(FxSaveArea->U.FnArea));
FpuInitialized = TRUE;
}
NpxThread->NpxState = NPX_STATE_VALID;
}
#endif /* !CONFIG_SMP */
/* restore the state of the current thread */
ASSERT((CurrentThread->NpxState & NPX_STATE_DIRTY) == 0);
FxSaveArea = (PFX_SAVE_AREA)((ULONG_PTR)CurrentThread->InitialStack - sizeof (FX_SAVE_AREA));
if (CurrentThread->NpxState & NPX_STATE_VALID)
{
if (KeI386FxsrPresent)
{
FxSaveArea->U.FxArea.MXCsr &= MxcsrFeatureMask;
asm volatile("fxrstor %0" : : "m"(FxSaveArea->U.FxArea));
}
else
{
asm volatile("frstor %0" : : "m"(FxSaveArea->U.FnArea));
}
}
else /* NpxState & NPX_STATE_INVALID */
{
DPRINT("Setting up clean FPU state\n");
if (KeI386FxsrPresent)
{
memset(&FxSaveArea->U.FxArea, 0, sizeof(FxSaveArea->U.FxArea));
FxSaveArea->U.FxArea.ControlWord = 0x037f;
if (KeI386XMMIPresent)
{
FxSaveArea->U.FxArea.MXCsr = 0x00001f80 & MxcsrFeatureMask;
}
asm volatile("fxrstor %0" : : "m"(FxSaveArea->U.FxArea));
}
else if (!FpuInitialized)
{
asm volatile("fninit");
}
}
KeGetCurrentPrcb()->NpxThread = CurrentThread;
#ifndef CONFIG_SMP
}
#endif
CurrentThread->NpxState |= NPX_STATE_DIRTY;
KeLowerIrql(oldIrql);
DPRINT("Device not present exception handled!\n");
return STATUS_SUCCESS;
}
else /* ExceptionNr == 16 || ExceptionNr == 19 */
{
EXCEPTION_RECORD Er;
KPROCESSOR_MODE PreviousMode;
PKTHREAD CurrentThread, NpxThread;
KIRQL OldIrql;
ULONG FpuEnvBuffer[7];
PFNSAVE_FORMAT FpuEnv = (PFNSAVE_FORMAT)FpuEnvBuffer;
ASSERT(ExceptionNr == 16 || ExceptionNr == 19); /* math fault or XMM fault*/
KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
NpxThread = KeGetCurrentPrcb()->NpxThread;
CurrentThread = KeGetCurrentThread();
if (NpxThread == NULL)
{
KeLowerIrql(OldIrql);
DPRINT("Math/Xmm fault ignored! (NpxThread == NULL)\n");
return STATUS_SUCCESS;
}
if (ExceptionNr == 16)
{
asm volatile("fnstenv %0" : : "m"(*FpuEnv));
asm volatile("fldenv %0" : : "m"(*FpuEnv)); /* Stupid x87... */
FpuEnv->StatusWord &= 0xffff;
}
KeLowerIrql(OldIrql);
PreviousMode = ((Tf->SegCs & 0xffff) == (KGDT_R3_CODE | RPL_MASK)) ? (UserMode) : (KernelMode);
DPRINT("Math/Xmm fault happened! (PreviousMode = %s)\n",
(PreviousMode != KernelMode) ? ("UserMode") : ("KernelMode"));
ASSERT(NpxThread == CurrentThread); /* FIXME: Is not always true I think */
/* Get FPU/XMM state */
KeLowerIrql(OldIrql);
/* Determine exception code */
if (ExceptionNr == 16)
{
DPRINT("FpuStatusWord = 0x%04x\n", FpuStatusWord);
if (FpuEnv->StatusWord & X87_SW_IE)
Er.ExceptionCode = STATUS_FLOAT_INVALID_OPERATION;
else if (FpuEnv->StatusWord & X87_SW_DE)
Er.ExceptionCode = STATUS_FLOAT_DENORMAL_OPERAND;
else if (FpuEnv->StatusWord & X87_SW_ZE)
Er.ExceptionCode = STATUS_FLOAT_DIVIDE_BY_ZERO;
else if (FpuEnv->StatusWord & X87_SW_OE)
Er.ExceptionCode = STATUS_FLOAT_OVERFLOW;
else if (FpuEnv->StatusWord & X87_SW_UE)
Er.ExceptionCode = STATUS_FLOAT_UNDERFLOW;
else if (FpuEnv->StatusWord & X87_SW_PE)
Er.ExceptionCode = STATUS_FLOAT_INEXACT_RESULT;
else if (FpuEnv->StatusWord & X87_SW_SE)
Er.ExceptionCode = STATUS_FLOAT_STACK_CHECK;
else
ASSERT(0); /* not reached */
Er.ExceptionAddress = (PVOID)FpuEnv->ErrorOffset;
}
else /* ExceptionNr == 19 */
{
Er.ExceptionCode = STATUS_FLOAT_MULTIPLE_TRAPS;
Er.ExceptionAddress = (PVOID)Tf->Eip;
}
Er.ExceptionFlags = 0;
Er.ExceptionRecord = NULL;
Er.NumberParameters = 0;
/* Dispatch exception */
DPRINT("Dispatching exception (ExceptionCode = 0x%08x)\n", Er.ExceptionCode);
KiDispatchException(&Er, NULL, Tf, PreviousMode, TRUE);
DPRINT("Math-fault handled!\n");
return STATUS_SUCCESS;
}
return STATUS_UNSUCCESSFUL;
}
/* This is a rather naive implementation of Ke(Save/Restore)FloatingPointState
which will not work for WDM drivers. Please feel free to improve */
NTSTATUS STDCALL
KeSaveFloatingPointState(OUT PKFLOATING_SAVE Save)
{
PFNSAVE_FORMAT FpState;
ASSERT_IRQL(DISPATCH_LEVEL);
/* check if we are doing software emulation */
if (!KeI386NpxPresent)
{
return STATUS_ILLEGAL_FLOAT_CONTEXT;
}
FpState = ExAllocatePool(NonPagedPool, sizeof (FNSAVE_FORMAT));
if (NULL == FpState)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
*((PVOID *) Save) = FpState;
#if defined(__GNUC__)
asm volatile("fnsave %0\n\t" : "=m" (*FpState));
#elif defined(_MSC_VER)
__asm mov eax, FpState;
__asm fsave [eax];
#else
#error Unknown compiler for inline assembler
#endif
KeGetCurrentThread()->DispatcherHeader.NpxIrql = KeGetCurrentIrql();
return STATUS_SUCCESS;
}
NTSTATUS STDCALL
KeRestoreFloatingPointState(IN PKFLOATING_SAVE Save)
{
PFNSAVE_FORMAT FpState = *((PVOID *) Save);
if (KeGetCurrentThread()->DispatcherHeader.NpxIrql != KeGetCurrentIrql())
{
KEBUGCHECK(UNDEFINED_BUG_CODE);
}
#if defined(__GNUC__)
asm volatile("fnclex\n\t");
asm volatile("frstor %0\n\t" : "=m" (*FpState));
#elif defined(_MSC_VER)
__asm mov eax, FpState;
__asm frstor [eax];
#else
#error Unknown compiler for inline assembler
#endif
ExFreePool(FpState);
return STATUS_SUCCESS;
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?