diff --git a/headers/private/kernel/arch/x86/64/cpu.h b/headers/private/kernel/arch/x86/64/cpu.h index 33358c60f8..3cc0ceb31f 100644 --- a/headers/private/kernel/arch/x86/64/cpu.h +++ b/headers/private/kernel/arch/x86/64/cpu.h @@ -9,13 +9,13 @@ #include -extern uint16 gFPUControlDefault; -extern uint32 gFPUMXCSRDefault; - - static inline void x86_context_switch(arch_thread* oldState, arch_thread* newState) { + uint16_t fpuControl; + asm volatile("fnstcw %0" : "=m" (fpuControl)); + uint32_t sseControl; + asm volatile("stmxcsr %0" : "=m" (sseControl)); asm volatile( "pushq %%rbp;" "movq $1f, %c[rip](%0);" @@ -32,8 +32,11 @@ x86_context_switch(arch_thread* oldState, arch_thread* newState) "r14", "r15", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15", "memory"); - asm volatile("ldmxcsr %0" : : "m" (gFPUMXCSRDefault)); - asm volatile("fldcw %0" : : "m" (gFPUControlDefault)); + asm volatile("fninit"); + // The kernel only needs FNCLEX (so that FLDCW won't trigger exceptions) + // but we must not leak x87 FPU state between teams, so reset it. + asm volatile("ldmxcsr %0" : : "m" (sseControl)); + asm volatile("fldcw %0" : : "m" (fpuControl)); } diff --git a/src/system/kernel/arch/x86/64/thread.cpp b/src/system/kernel/arch/x86/64/thread.cpp index d0192f3f2f..64b2b9cd9f 100644 --- a/src/system/kernel/arch/x86/64/thread.cpp +++ b/src/system/kernel/arch/x86/64/thread.cpp @@ -71,8 +71,6 @@ extern "C" void x86_64_thread_entry(); // Initial thread saved state. static arch_thread sInitialState _ALIGNED(64); -uint16 gFPUControlDefault; -uint32 gFPUMXCSRDefault; extern uint64 gFPUSaveLength; extern bool gHasXsave; extern bool gHasXsavec; @@ -175,7 +173,6 @@ arch_thread_init(kernel_args* args) // Save one global valid FPU state; it will be copied in the arch dependent // part of each new thread. if (gHasXsave || gHasXsavec) { - memset(sInitialState.fpu_state, 0, gFPUSaveLength); if (gHasXsavec) { asm volatile ( "clts;" \ @@ -203,11 +200,15 @@ arch_thread_init(kernel_args* args) "fxsaveq %0" :: "m" (sInitialState.fpu_state)); } - gFPUControlDefault = ((savefpu*)&sInitialState.fpu_state)->fp_fxsave.control; - gFPUMXCSRDefault = ((savefpu*)&sInitialState.fpu_state)->fp_fxsave.mxcsr; + + // FNINIT does not affect MXCSR or data registers, so we reset them in the state. + savefpu* initialState = ((savefpu*)&sInitialState.fpu_state); + initialState->fp_fxsave.mxcsr = 0x1F80; // __INITIAL_MXCSR__ + memset(initialState->fp_fxsave.fp, 0, sizeof(initialState->fp_fxsave.fp)); + memset(initialState->fp_fxsave.xmm, 0, sizeof(initialState->fp_fxsave.xmm)); + memset(initialState->fp_ymm, 0, sizeof(initialState->fp_ymm)); register_generic_syscall(THREAD_SYSCALLS, arch_thread_control, 1, 0); - return B_OK; }