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 | 40 +++++++++++++++++++++++ dlls/ntdll/unix/signal_x86_64.c | 56 +++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+)
diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c index 91c4ec3d0eb..36a8c630f11 100644 --- a/dlls/ntdll/unix/signal_i386.c +++ b/dlls/ntdll/unix/signal_i386.c @@ -493,6 +493,7 @@ C_ASSERT( offsetof( TEB, GdiTebBatch ) + offsetof( struct x86_thread_data, sysca #define SYSCALL_HAVE_XSAVE 1 #define SYSCALL_HAVE_XSAVEC 2 #define SYSCALL_HAVE_FXSAVE 4 +#define SYSCALL_NEED_XSTATE 8
static unsigned int syscall_flags;
@@ -741,6 +742,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_NEED_XSTATE) + { + 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 +1628,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 $~8,%eax\n\t" /* syscall_flags &= ~SYSCALL_NEED_XSTATE */ "movl %eax,(%esp)\n\t" "movl 0x38(%ecx),%eax\n\t" /* frame->syscall_table */ "movl %eax,0x38(%esp)\n\t" @@ -2077,6 +2111,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 ); @@ -2570,6 +2605,10 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, "shrl $8,%ebx\n\t" "andl $0x30,%ebx\n\t" /* syscall table number */ "addl 0x38(%ecx),%ebx\n\t" /* frame->syscall_table */ + "testl $0x80000000,%eax\n\t" + "jz .L__wine_syscall_dispatcher_save_fpu\n\t" + "orl $0x10,(%ecx)\n\t" /* frame->syscall_flags |= SYSCALL_NEED_XSTATE */ + "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) */ @@ -2657,6 +2696,7 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, "fwait\n\t"
"\n.L__wine_syscall_dispatcher_fpu_restored:\n\t" + "andl $~8,0(%esp)\n\t" /* frame->syscall_flags &= ~SYSCALL_NEED_XSTATE */ "movl 0x2c(%esp),%edi\n\t" __ASM_CFI(".cfi_remember_state\n\t") __ASM_CFI(".cfi_same_value %edi\n\t") diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index e98c0299b80..b7050bcd0ff 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -364,6 +364,7 @@ C_ASSERT( sizeof(struct stack_layout) == 0x590 ); /* Should match the size in ca #define SYSCALL_HAVE_XSAVEC 2 #define SYSCALL_HAVE_PTHREAD_TEB 4 #define SYSCALL_HAVE_WRFSGSBASE 8 +#define SYSCALL_NEED_XSTATE 0x10
static unsigned int syscall_flags;
@@ -823,6 +824,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_NEED_XSTATE) && 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 +1634,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 $~0x10,%r14d\n\t" /* syscall_flags &= ~SYSCALL_NEED_XSTATE */ "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 +2178,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 ); @@ -2648,6 +2675,21 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, * depends on us returning to it. Adjust the return address accordingly. */ "subq $0xb,0x70(%rcx)\n\t" "movl 0xb0(%rcx),%r14d\n\t" /* frame->syscall_flags */ + "testl $0x80000000,%eax\n\t" + "jz .L__wine_syscall_dispatcher_save_fpu\n\t" + "orq $0x10,%r14\n\t" + "movq %r14,0xb0(%rcx)\n\t" /* frame->syscall_flags |= SYSCALL_NEED_XSTATE */ + "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 */ @@ -2742,7 +2784,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 $0x10,%r14d\n\t" /* SYSCALL_NEED_XSTATE */ "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 */ @@ -2758,6 +2813,7 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher, "fxrstor64 0xc0(%rcx)\n\t"
"\n.L__wine_syscall_dispatcher_fpu_restored:\n\t" + "andl $~0x10,0xb0(%rcx)\n\t" /* frame->syscall_flags &= ~SYSCALL_NEED_XSTATE */ "movq 0x98(%rcx),%rbp\n\t" __ASM_CFI(".cfi_same_value rbp\n\t") "movq 0x68(%rcx),%r15\n\t"