- Small patch to fix (delayed) loading of floating point state. Enables the special handling of fpu exceptions caused by frstor when used by the kernel, by implementing its use in assembly so the trap handler gets the instruction address it needs (for ALl compilers!). May or may not fix the fact that floating point state is not properly saved between threads.

See CORE-10005.

svn path=/trunk/; revision=68886
This commit is contained in:
Stefan Ginsberg 2015-09-01 00:20:57 +00:00
parent bb8a6e700c
commit fdeca1b2b2
4 changed files with 35 additions and 25 deletions

View file

@ -50,21 +50,6 @@ Ke386SaveFpuState(IN PFX_SAVE_AREA 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
USHORT
Ke386GetLocalDescriptorTable()

View file

@ -541,7 +541,6 @@ extern VOID NTAPI ExpInterlockedPopEntrySListFault(VOID);
extern VOID NTAPI ExpInterlockedPopEntrySListResume(VOID);
extern VOID __cdecl CopyParams(VOID);
extern VOID __cdecl ReadBatch(VOID);
extern VOID __cdecl FrRestore(VOID);
extern CHAR KiSystemCallExitBranch[];
extern CHAR KiSystemCallExit[];
extern CHAR KiSystemCallExit2[];

View file

@ -159,4 +159,28 @@ PUBLIC @Ki386BiosCallReturnAddress@4
popad
ret 4
PUBLIC _FrRestore
PUBLIC @Ke386LoadFpuState@4
@Ke386LoadFpuState@4:
/* Check if we have FXSR and choose which operand to use */
test byte ptr [_KeI386FxsrPresent], 1
jz _FrRestore
/* Restore all the FPU, MMX, XMM and MXCSR registers */
fxrstor [ecx]
ret
/*
* Just restore the basic FPU registers.
* This may raise an exception depending
* on the status word, which KiNpxHandler will
* need to check for and handle during delayed load
* to avoid raising an unhandled exception
* and crashing the system.
*/
_FrRestore:
frstor [ecx]
ret
END

View file

@ -15,6 +15,9 @@
VOID KiFastCallEntry(VOID);
VOID KiFastCallEntryWithSingleStep(VOID);
extern PVOID FrRestore;
VOID FASTCALL Ke386LoadFpuState(IN PFX_SAVE_AREA SaveArea);
/* GLOBALS ********************************************************************/
UCHAR KiTrapPrefixTable[] =
@ -251,16 +254,16 @@ KiNpxHandler(IN PKTRAP_FRAME TrapFrame,
SaveArea->Cr0NpxState |= CR0_TS;
/* Only valid if it happened during a restore */
//if ((PVOID)TrapFrame->Eip == FrRestore)
if ((PVOID)TrapFrame->Eip == FrRestore)
{
/* It did, so just skip the instruction */
//TrapFrame->Eip += 3; /* sizeof(FRSTOR) */
//KiEoiHelper(TrapFrame);
TrapFrame->Eip += 3; /* Size of FRSTOR instruction */
KiEoiHelper(TrapFrame);
}
}
/* User or kernel trap -- get ready to issue an exception */
//if (Thread->NpxState == NPX_STATE_NOT_LOADED)
if (Thread->NpxState == NPX_STATE_NOT_LOADED)
{
/* Update CR0 */
Cr0 = __readcr0();
@ -744,7 +747,7 @@ KiTrap07Handler(IN PKTRAP_FRAME TrapFrame)
KiEnterTrap(TrapFrame);
/* Try to handle NPX delay load */
while (TRUE)
for (;;)
{
/* Get the current thread */
Thread = KeGetCurrentThread();
@ -775,15 +778,14 @@ KiTrap07Handler(IN PKTRAP_FRAME TrapFrame)
NpxSaveArea = KiGetThreadNpxArea(NpxThread);
/* Save FPU state */
DPRINT("FIXME: Save FPU state: %p\n", NpxSaveArea);
//Ke386SaveFpuState(NpxSaveArea);
Ke386SaveFpuState(NpxSaveArea);
/* Update NPX state */
NpxThread->NpxState = NPX_STATE_NOT_LOADED;
}
/* Load FPU state */
//Ke386LoadFpuState(SaveArea);
Ke386LoadFpuState(SaveArea);
/* Update NPX state */
Thread->NpxState = NPX_STATE_LOADED;
@ -823,7 +825,7 @@ KiTrap07Handler(IN PKTRAP_FRAME TrapFrame)
{
/*
* 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.
* but we could have lost track of that due to a BIOS call.
* Make sure MP is still set, which should verify the theory.
*/
if (Cr0 & CR0_MP)