From: Rémi Bernon rbernon@codeweavers.com
Using the signal context for the volatile FPU state, assuming that it hasn't been modified by the unix call. --- dlls/ntdll/unix/signal_i386.c | 41 ++++++++++++++++++++++++ dlls/ntdll/unix/signal_x86_64.c | 56 +++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+)
diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c index ed344d11e1b..a321562c21c 100644 --- a/dlls/ntdll/unix/signal_i386.c +++ b/dlls/ntdll/unix/signal_i386.c @@ -741,6 +741,38 @@ static inline void restore_fpu( const CONTEXT *context ) }
+/*********************************************************************** + * update_frame_context + * + * Update current syscall frame context from a sigcontext. + */ +static void update_frame_context( const ucontext_t *sigcontext ) +{ + struct syscall_frame *frame = x86_thread_data()->syscall_frame; + + if (frame->syscall_flags & SYSCALL_FLAG_NOFPU) + { + FLOATING_SAVE_AREA *fpu = FPU_sig(sigcontext); + XSAVE_FORMAT *fpux = FPUX_sig(sigcontext); + + if (fpu) fpu_to_fpux( &frame->u.xsave, fpu ); + if (fpux) + { + XSTATE *xs; + if (!fpu) frame->u.xsave = *fpux; + if ((cpu_info.ProcessorFeatureBits & CPU_FEATURE_AVX) && (xs = XState_sig(fpux))) + frame->xstate = *xs; + } + if (!fpu && !fpux) + { + CONTEXT context; + save_fpu( &context ); + fpu_to_fpux( &frame->u.xsave, &context.FloatSave ); + } + } +} + + /*********************************************************************** * save_context * @@ -1595,6 +1627,7 @@ __ASM_GLOBAL_FUNC( call_user_mode_callback, "movl %ebp,0x380(%esp)\n\t" "movl 0x1f8(%edx),%ecx\n\t" /* x86_thread_data()->syscall_frame */ "movl (%ecx),%eax\n\t" /* frame->syscall_flags */ + "andl $~0x80000000,%eax\n\t" /* syscall_flags &= ~SYSCALL_FLAG_NOFPU */ "movl %eax,(%esp)\n\t" "movl 0x38(%ecx),%eax\n\t" /* frame->syscall_table */ "movl %eax,0x38(%esp)\n\t" @@ -2076,6 +2109,7 @@ static void usr1_handler( int signal, siginfo_t *siginfo, void *sigcontext ) DECLSPEC_ALIGN(64) XSTATE xs; xcontext.c.ContextFlags = CONTEXT_FULL; context_init_xstate( &xcontext.c, &xs ); + update_frame_context( sigcontext );
NtGetContextThread( GetCurrentThread(), &xcontext.c ); wait_suspend( &xcontext.c ); @@ -2575,6 +2609,12 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, "andl $0xfff,%eax\n\t" /* syscall number */ "cmpl 8(%ebx),%eax\n\t" /* table->ServiceLimit */ "jae .L__wine_syscall_dispatcher_invalid_arg\n\t" + "movl 4(%ebx),%edx\n\t" /* table->CounterTable */ + "movl (%edx,%eax,4),%edx\n\t" + "orl %edx,(%ecx)\n\t" /* frame->syscall_flags |= syscall_flags */ + "testl $0x80000000,(%ecx)\n\t" /* frame->syscall_flags & SYSCALL_FLAG_NOFPU */ + "jz .L__wine_syscall_dispatcher_save_fpu\n\t" + "jmp .L__wine_syscall_dispatcher_fpu_saved\n\t"
"\n.L__wine_syscall_dispatcher_save_fpu:\n\t" "testl $3,(%ecx)\n\t" /* frame->syscall_flags & (SYSCALL_HAVE_XSAVE | SYSCALL_HAVE_XSAVEC) */ @@ -2661,6 +2701,7 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, "fwait\n\t"
"\n.L__wine_syscall_dispatcher_fpu_restored:\n\t" + "andl $~0x80000000,0(%esp)\n\t" /* frame->syscall_flags &= ~SYSCALL_FLAG_NOFPU */ "movl 0x2c(%esp),%edi\n\t" /* remember state when $esp is pointing to "frame" */ __ASM_CFI(".cfi_remember_state\n\t") diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index 798de6d6c28..9472acdbb26 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -823,6 +823,30 @@ static inline void leave_handler( const ucontext_t *sigcontext ) }
+/*********************************************************************** + * update_frame_context + * + * Update current syscall frame context from a sigcontext. + */ +static void update_frame_context( const ucontext_t *sigcontext ) +{ + struct syscall_frame *frame = amd64_thread_data()->syscall_frame; + + if ((frame->syscall_flags & SYSCALL_FLAG_NOFPU) && FPU_sig(sigcontext)) + { + M128A tmp[10]; + XSTATE *xs; + + memcpy( &tmp, frame->xsave.XmmRegisters + 6, sizeof(tmp) ); + frame->xsave = *FPU_sig(sigcontext); + memcpy( frame->xsave.XmmRegisters + 6, &tmp, sizeof(tmp) ); + + if ((cpu_info.ProcessorFeatureBits & CPU_FEATURE_AVX) && (xs = XState_sig(FPU_sig(sigcontext)))) + frame->xstate = *xs; + } +} + + /*********************************************************************** * save_context * @@ -1609,6 +1633,7 @@ __ASM_GLOBAL_FUNC( call_user_mode_callback, "movq 0xa8(%r10),%rax\n\t" /* prev_frame->syscall_table */ "movq %rax,0xa8(%rsp)\n\t" /* frame->syscall_table */ "movl 0xb0(%r10),%r14d\n\t" /* prev_frame->syscall_flags */ + "andl $~0x80000000,%r14d\n\t" /* syscall_flags &= ~SYSCALL_FLAG_NOFPU */ "movl %r14d,0xb0(%rsp)\n\t" /* frame->syscall_flags */ "movq %r10,0xa0(%rsp)\n\t" /* frame->prev_frame */ "movq %rsp,0x328(%r11)\n\t" /* amd64_thread_data()->syscall_frame */ @@ -2152,6 +2177,7 @@ static void usr1_handler( int signal, siginfo_t *siginfo, void *ucontext ) DECLSPEC_ALIGN(64) XSTATE xs; context.c.ContextFlags = CONTEXT_FULL; context_init_xstate( &context.c, &xs ); + update_frame_context( ucontext );
NtGetContextThread( GetCurrentThread(), &context.c ); wait_suspend( &context.c ); @@ -2663,6 +2689,22 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, "andl $0xfff,%eax\n\t" /* syscall number */ "cmpq 16(%rbx),%rax\n\t" /* table->ServiceLimit */ "jae .L__wine_syscall_dispatcher_invalid_arg\n\t" + "movq 8(%rbx),%rdx\n\t" /* table->CounterTable */ + "orq (%rdx,%rax,8),%r14\n\t" + "movq %r14,0xb0(%rcx)\n\t" /* frame->syscall_flags |= syscall_flags */ + "testl $0x80000000,%r14d\n\t" /* SYSCALL_FLAG_NOFPU */ + "jz .L__wine_syscall_dispatcher_save_fpu\n\t" + "movdqa %xmm6,0x1c0(%rcx)\n\t" + "movdqa %xmm7,0x1d0(%rcx)\n\t" + "movdqa %xmm8,0x1e0(%rcx)\n\t" + "movdqa %xmm9,0x1f0(%rcx)\n\t" + "movdqa %xmm10,0x200(%rcx)\n\t" + "movdqa %xmm11,0x210(%rcx)\n\t" + "movdqa %xmm12,0x220(%rcx)\n\t" + "movdqa %xmm13,0x230(%rcx)\n\t" + "movdqa %xmm14,0x240(%rcx)\n\t" + "movdqa %xmm15,0x250(%rcx)\n\t" + "jmp .L__wine_syscall_dispatcher_fpu_saved\n\t"
"\n.L__wine_syscall_dispatcher_save_fpu:\n\t" "testl $3,%r14d\n\t" /* SYSCALL_HAVE_XSAVE | SYSCALL_HAVE_XSAVEC */ @@ -2750,7 +2792,20 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, "\n.L__wine_syscall_dispatcher_fsgs_restored:\n\t" #endif "testl $0x48,%edx\n\t" /* CONTEXT_FLOATING_POINT | CONTEXT_XSTATE */ + "jnz .L__wine_syscall_dispatcher_restore_fpu\n\t" + "testl $0x80000000,%r14d\n\t" /* SYSCALL_FLAG_NOFPU */ "jz .L__wine_syscall_dispatcher_fpu_restored\n\t" + "movdqa 0x1c0(%rcx),%xmm6\n\t" + "movdqa 0x1d0(%rcx),%xmm7\n\t" + "movdqa 0x1e0(%rcx),%xmm8\n\t" + "movdqa 0x1f0(%rcx),%xmm9\n\t" + "movdqa 0x200(%rcx),%xmm10\n\t" + "movdqa 0x210(%rcx),%xmm11\n\t" + "movdqa 0x220(%rcx),%xmm12\n\t" + "movdqa 0x230(%rcx),%xmm13\n\t" + "movdqa 0x240(%rcx),%xmm14\n\t" + "movdqa 0x250(%rcx),%xmm15\n\t" + "jmp .L__wine_syscall_dispatcher_fpu_restored\n\t"
"\n.L__wine_syscall_dispatcher_restore_fpu:\n\t" "testl $3,%r14d\n\t" /* SYSCALL_HAVE_XSAVE | SYSCALL_HAVE_XSAVEC */ @@ -2766,6 +2821,7 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, "fxrstor64 0xc0(%rcx)\n\t"
"\n.L__wine_syscall_dispatcher_fpu_restored:\n\t" + "andl $~0x80000000,0xb0(%rcx)\n\t" /* frame->syscall_flags &= ~SYSCALL_FLAG_NOFPU */ "movq 0x98(%rcx),%rbp\n\t" __ASM_CFI(".cfi_same_value rbp\n\t") "movq 0x68(%rcx),%r15\n\t"