diff --git a/dlls/ntdll/unix/signal_arm.c b/dlls/ntdll/unix/signal_arm.c index cb4695939f5..5c96521e55e 100644 --- a/dlls/ntdll/unix/signal_arm.c +++ b/dlls/ntdll/unix/signal_arm.c @@ -918,6 +918,7 @@ void signal_init_threading(void) */ NTSTATUS signal_alloc_thread( TEB *teb ) { + teb->WOW32Reserved = __wine_syscall_dispatcher; return STATUS_SUCCESS; } diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c index 0234c7aa6f7..7e383bdcaba 100644 --- a/dlls/ntdll/unix/signal_i386.c +++ b/dlls/ntdll/unix/signal_i386.c @@ -461,6 +461,17 @@ enum i386_trap_code #endif }; +struct syscall_xsave +{ + union + { + XSAVE_FORMAT xsave; + FLOATING_SAVE_AREA fsave; + } u; +}; + +C_ASSERT( sizeof(struct syscall_xsave) == 0x200 ); + struct syscall_frame { DWORD eflags; /* 00 */ @@ -502,6 +513,8 @@ C_ASSERT( offsetof( TEB, GdiTebBatch ) + offsetof( struct x86_thread_data, gs ) C_ASSERT( offsetof( TEB, GdiTebBatch ) + offsetof( struct x86_thread_data, exit_frame ) == 0x1f4 ); C_ASSERT( offsetof( TEB, GdiTebBatch ) + offsetof( struct x86_thread_data, syscall_frame ) == 0x1f8 ); +static void *syscall_dispatcher; + static inline struct x86_thread_data *x86_thread_data(void) { return (struct x86_thread_data *)ntdll_get_thread_data()->cpu_data; @@ -2424,6 +2437,7 @@ NTSTATUS signal_alloc_thread( TEB *teb ) } else thread_data->fs = gdt_fs_sel; + teb->WOW32Reserved = syscall_dispatcher; return STATUS_SUCCESS; } @@ -2501,7 +2515,14 @@ void signal_init_process(void) */ void *signal_init_syscalls(void) { - return __wine_syscall_dispatcher; + extern void __wine_syscall_dispatcher_fxsave(void) DECLSPEC_HIDDEN; + + if (cpu_info.FeatureSet & CPU_FEATURE_FXSR) + syscall_dispatcher = __wine_syscall_dispatcher_fxsave; + else + syscall_dispatcher = __wine_syscall_dispatcher; + + return NtCurrentTeb()->WOW32Reserved = syscall_dispatcher; } diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index 3350dc665c1..a707faae2a5 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -2556,7 +2556,6 @@ static void init_teb( TEB *teb, PEB *peb ) PtrToUlong( &teb64->ActivationContextStack.FrameListCache ); teb64->StaticUnicodeString.Buffer = PtrToUlong( teb64->StaticUnicodeBuffer ); teb64->StaticUnicodeString.MaximumLength = sizeof( teb64->StaticUnicodeBuffer ); - teb->WOW32Reserved = __wine_syscall_dispatcher; #endif teb->Peb = peb; teb->Tib.Self = &teb->Tib; diff --git a/tools/winebuild/import.c b/tools/winebuild/import.c index c760903dbd1..53d77a19e23 100644 --- a/tools/winebuild/import.c +++ b/tools/winebuild/import.c @@ -1456,7 +1456,19 @@ static void output_syscall_dispatcher( int count, const char *variant ) output( "\tmovl %%ecx,-0x28(%%ebp)\n" ); /* frame->esp */ output( "\tmovl 4(%%ebp),%%ecx\n" ); output( "\tmovl %%ecx,-0x2c(%%ebp)\n" ); /* frame->eip */ - output( "\tmovl %%esp,%%fs:0x1f8\n" ); /* x86_thread_data()->syscall_frame */ + output( "\tsubl $0x200,%%esp\n") ; + output( "\tandl $~63,%%esp\n" ); + if (!*variant) + { + output( "\tfnsave (%%esp)\n" ); + output( "\tfwait\n" ); + } + else + { + output( "\tfxsave (%%esp)\n" ); + } + output( "\tleal -0x30(%%ebp),%%ecx\n" ); + output( "\tmovl %%ecx,%%fs:0x1f8\n" ); /* x86_thread_data()->syscall_frame */ output( "\tcmpl $%u,%%eax\n", count ); output( "\tjae 4f\n" ); if (UsePIC) @@ -1479,6 +1491,17 @@ static void output_syscall_dispatcher( int count, const char *variant ) else output( "\tcall *.Lsyscall_table(,%%eax,4)\n" ); output( "2:\tmovl $0,%%fs:0x1f8\n" ); + output( "\tleal -0x230(%%ebp),%%ebx\n") ; + output( "\tandl $~63,%%ebx\n" ); + if (!*variant) + { + output( "\tfrstor (%%ebx)\n" ); + output( "\tfwait\n" ); + } + else + { + output( "\tfxrstor (%%ebx)\n" ); + } output( "\tleal -0x30(%%ebp),%%ebx\n" ); output_cfi( ".cfi_def_cfa_register %%ebx" ); output_cfi( ".cfi_adjust_cfa_offset 0x30\n" ); @@ -1792,6 +1815,9 @@ void output_syscalls( DLLSPEC *spec ) switch( target_cpu ) { + case CPU_x86: + output_syscall_dispatcher( count, "_fxsave" ); + break; case CPU_x86_64: output_syscall_dispatcher( count, "_xsave" ); output_syscall_dispatcher( count, "_xsavec" );