From fdeca1b2b2f1c3a831efb684da3121e00986c027 Mon Sep 17 00:00:00 2001 From: Stefan Ginsberg Date: Tue, 1 Sep 2015 00:20:57 +0000 Subject: [PATCH] - 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 --- .../ntoskrnl/include/internal/i386/intrin_i.h | 15 ------------ reactos/ntoskrnl/include/internal/i386/ke.h | 1 - reactos/ntoskrnl/ke/i386/ctxswitch.S | 24 +++++++++++++++++++ reactos/ntoskrnl/ke/i386/traphdlr.c | 20 +++++++++------- 4 files changed, 35 insertions(+), 25 deletions(-) diff --git a/reactos/ntoskrnl/include/internal/i386/intrin_i.h b/reactos/ntoskrnl/include/internal/i386/intrin_i.h index 3a2664ba5b4..35cfd8ecbcc 100644 --- a/reactos/ntoskrnl/include/internal/i386/intrin_i.h +++ b/reactos/ntoskrnl/include/internal/i386/intrin_i.h @@ -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() diff --git a/reactos/ntoskrnl/include/internal/i386/ke.h b/reactos/ntoskrnl/include/internal/i386/ke.h index cfe674c3dec..a610734a611 100644 --- a/reactos/ntoskrnl/include/internal/i386/ke.h +++ b/reactos/ntoskrnl/include/internal/i386/ke.h @@ -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[]; diff --git a/reactos/ntoskrnl/ke/i386/ctxswitch.S b/reactos/ntoskrnl/ke/i386/ctxswitch.S index 3491fcb6eba..3a35a3aa60d 100644 --- a/reactos/ntoskrnl/ke/i386/ctxswitch.S +++ b/reactos/ntoskrnl/ke/i386/ctxswitch.S @@ -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 diff --git a/reactos/ntoskrnl/ke/i386/traphdlr.c b/reactos/ntoskrnl/ke/i386/traphdlr.c index 4170a7b13b1..9e5defed420 100644 --- a/reactos/ntoskrnl/ke/i386/traphdlr.c +++ b/reactos/ntoskrnl/ke/i386/traphdlr.c @@ -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)