ntdll: Use a single syscall dispatcher controlled by global flags on x86-64.

Based on a patch by Jacek Caban.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2021-06-02 12:02:41 +02:00
parent 96030ce738
commit 3d9cb5e4f8
3 changed files with 56 additions and 64 deletions

View file

@ -251,6 +251,10 @@ C_ASSERT((offsetof(struct stack_layout, xstate) == sizeof(struct stack_layout)))
C_ASSERT( sizeof(XSTATE) == 0x140 );
C_ASSERT( sizeof(struct stack_layout) == 0x590 ); /* Should match the size in call_user_exception_dispatcher(). */
/* flags to control the behavior of the syscall dispatcher */
#define SYSCALL_HAVE_XSAVE 1
#define SYSCALL_HAVE_XSAVEC 2
/* stack layout when calling an user apc function.
* FIXME: match Windows ABI. */
struct apc_stack_layout
@ -2653,6 +2657,9 @@ void signal_init_process(void)
{
struct sigaction sig_act;
if (cpu_info.ProcessorFeatureBits & CPU_FEATURE_XSAVE) __wine_syscall_flags |= SYSCALL_HAVE_XSAVE;
if (xstate_compaction_enabled) __wine_syscall_flags |= SYSCALL_HAVE_XSAVEC;
sig_act.sa_mask = server_block_set;
sig_act.sa_flags = SA_SIGINFO | SA_RESTART | SA_ONSTACK;
@ -2685,24 +2692,14 @@ void signal_init_process(void)
*/
void *signal_init_syscalls(void)
{
void *ptr, *syscall_dispatcher;
extern void __wine_syscall_dispatcher_xsave(void) DECLSPEC_HIDDEN;
extern void __wine_syscall_dispatcher_xsavec(void) DECLSPEC_HIDDEN;
if (xstate_compaction_enabled)
syscall_dispatcher = __wine_syscall_dispatcher_xsavec;
else if (cpu_info.ProcessorFeatureBits & CPU_FEATURE_XSAVE)
syscall_dispatcher = __wine_syscall_dispatcher_xsave;
else
syscall_dispatcher = __wine_syscall_dispatcher;
void *ptr;
/* sneak in a syscall dispatcher pointer at a fixed address (7ffe1000) */
ptr = (char *)user_shared_data + page_size;
anon_mmap_fixed( ptr, page_size, PROT_READ | PROT_WRITE, 0 );
*(void **)ptr = syscall_dispatcher;
*(void **)ptr = __wine_syscall_dispatcher;
return syscall_dispatcher;
return __wine_syscall_dispatcher;
}

View file

@ -248,6 +248,7 @@ extern void DECLSPEC_NORETURN signal_start_thread( PRTL_THREAD_START_ROUTINE ent
BOOL suspend, void *thunk, TEB *teb ) DECLSPEC_HIDDEN;
extern void DECLSPEC_NORETURN signal_exit_thread( int status, void (*func)(int) ) DECLSPEC_HIDDEN;
extern void __wine_syscall_dispatcher(void) DECLSPEC_HIDDEN;
extern unsigned int __wine_syscall_flags DECLSPEC_HIDDEN;
extern void signal_restore_full_cpu_context(void) DECLSPEC_HIDDEN;
extern NTSTATUS get_thread_wow64_context( HANDLE handle, void *ctx, ULONG size ) DECLSPEC_HIDDEN;
extern NTSTATUS set_thread_wow64_context( HANDLE handle, const void *ctx, ULONG size ) DECLSPEC_HIDDEN;

View file

@ -1621,45 +1621,43 @@ static void output_syscall_dispatcher( const char *variant )
output( "\tmovw %%ss,-0x8(%%rbp)\n" );
output( "\tmovw %%gs,-0x6(%%rbp)\n" );
output( "\tmovq %%rsp,%%r12\n" );
output( "\tmovq %%rax,%%r11\n" );
if (!*variant)
{
output( "\tfxsave64 (%%r12)\n" );
}
else
{
output( "\tmovl $7,%%eax\n" );
output( "\tmovq %%rdx,%%rsi\n" );
output( "\txorq %%rdx,%%rdx\n" );
output( "\tmovq %%rdx,0x200(%%r12)\n" );
output( "\tmovq %%rdx,0x208(%%r12)\n" );
output( "\tmovq %%rdx,0x210(%%r12)\n" );
if (!strcmp( variant, "_xsavec" ))
{
output( "\tmovq %%rdx,0x218(%%r12)\n" );
output( "\tmovq %%rdx,0x220(%%r12)\n" );
output( "\tmovq %%rdx,0x228(%%r12)\n" );
output( "\tmovq %%rdx,0x230(%%r12)\n" );
output( "\tmovq %%rdx,0x238(%%r12)\n" );
output( "\txsavec64 (%%r12)\n" );
}
else
output( "\txsave64 (%%r12)\n" );
output( "\tmovq %%rsi,%%rdx\n" );
}
output( "\tmovq %%gs:0x30,%%rcx\n" );
output( "\tmovq %%rax,%%r13\n" );
output( "\tmovl %s(%%rip),%%r14d\n", asm_name("__wine_syscall_flags") );
output( "\ttestl $3,%%r14d\n" ); /* SYSCALL_HAVE_XSAVE | SYSCALL_HAVE_XSAVEC */
output( "\tjz 2f\n" );
output( "\tmovl $7,%%eax\n" );
output( "\tmovq %%rdx,%%rsi\n" );
output( "\txorq %%rdx,%%rdx\n" );
output( "\tmovq %%rdx,0x200(%%r12)\n" );
output( "\tmovq %%rdx,0x208(%%r12)\n" );
output( "\tmovq %%rdx,0x210(%%r12)\n" );
output( "\ttestl $2,%%r14d\n" ); /* SYSCALL_HAVE_XSAVEC */
output( "\tjz 1f\n" );
output( "\tmovq %%rdx,0x218(%%r12)\n" );
output( "\tmovq %%rdx,0x220(%%r12)\n" );
output( "\tmovq %%rdx,0x228(%%r12)\n" );
output( "\tmovq %%rdx,0x230(%%r12)\n" );
output( "\tmovq %%rdx,0x238(%%r12)\n" );
output( "\txsavec64 (%%r12)\n" );
output( "\tmovq %%rsi,%%rdx\n" );
output( "\tjmp 3f\n" );
output( "1:\txsave64 (%%r12)\n" );
output( "\tmovq %%rsi,%%rdx\n" );
output( "\tjmp 3f\n" );
output( "2:\tfxsave64 (%%r12)\n" );
output( "3:\tmovq %%gs:0x30,%%rcx\n" );
output( "\tleaq -0x98(%%rbp),%%rbx\n" );
output( "\tmovq %%rbx,0x328(%%rcx)\n" ); /* amd64_thread_data()->syscall_frame */
output( "\tmovq %%r11,%%rbx\n" );
output( "\tmovq %%r13,%%rbx\n" );
output( "\tshrl $8,%%ebx\n" );
output( "\tandl $0x30,%%ebx\n" ); /* syscall table number */
output( "\tleaq %s(%%rip),%%rcx\n", asm_name("KeServiceDescriptorTable") );
output( "\tleaq (%%rcx,%%rbx,2),%%rbx\n" );
output( "\tandq $0xfff,%%r11\n" ); /* syscall number */
output( "\tcmpq 16(%%rbx),%%r11\n" ); /* table->ServiceLimit */
output( "\tjae 3f\n" );
output( "\tandq $0xfff,%%r13\n" ); /* syscall number */
output( "\tcmpq 16(%%rbx),%%r13\n" ); /* table->ServiceLimit */
output( "\tjae 5f\n" );
output( "\tmovq 24(%%rbx),%%rcx\n" ); /* table->ArgumentTable */
output( "\tmovzbl (%%rcx,%%r11),%%ecx\n" );
output( "\tmovzbl (%%rcx,%%r13),%%ecx\n" );
output( "\tsubq $0x20,%%rcx\n" );
output( "\tjbe 1f\n" );
output( "\tsubq %%rcx,%%rsp\n" );
@ -1672,22 +1670,19 @@ static void output_syscall_dispatcher( const char *variant )
output( "1:\tmovq %%r10,%%rcx\n" );
output( "\tsubq $0x20,%%rsp\n" );
output( "\tmovq (%%rbx),%%r10\n" ); /* table->ServiceTable */
output( "\tcallq *(%%r10,%%r11,8)\n" );
output( "\tcallq *(%%r10,%%r13,8)\n" );
output( "2:\tmovq %%gs:0x30,%%rcx\n" );
output( "\tmovq $0,0x328(%%rcx)\n" );
if (!*variant)
{
output( "\tfxrstor64 (%%r12)\n" );
}
else
{
output( "\tmovq %%rax,%%r11\n" );
output( "\tmovl $7,%%eax\n" );
output( "\txorq %%rdx,%%rdx\n" );
output( "\txrstor64 (%%r12)\n" );
output( "\tmovq %%r11,%%rax\n" );
}
output( "\tmovq -0x30(%%rbp),%%r15\n" );
output( "\ttestl $3,%%r14d\n" ); /* SYSCALL_HAVE_XSAVE | SYSCALL_HAVE_XSAVEC */
output( "\tjz 3f\n" );
output( "\tmovq %%rax,%%r11\n" );
output( "\tmovl $7,%%eax\n" );
output( "\txorq %%rdx,%%rdx\n" );
output( "\txrstor64 (%%r12)\n" );
output( "\tmovq %%r11,%%rax\n" );
output( "\tjmp 4f\n" );
output( "3:\tfxrstor64 (%%r12)\n" );
output( "4:\tmovq -0x30(%%rbp),%%r15\n" );
output( "\tmovq -0x38(%%rbp),%%r14\n" );
output( "\tmovq -0x40(%%rbp),%%r13\n" );
output( "\tmovq -0x48(%%rbp),%%r12\n" );
@ -1704,7 +1699,7 @@ static void output_syscall_dispatcher( const char *variant )
output( "\tmovq (%%rbp),%%rbp\n" );
output_cfi( ".cfi_same_value %%rbp" );
output( "\tiretq\n" );
output( "3:\tmovl $0x%x,%%eax\n", invalid_param );
output( "5:\tmovl $0x%x,%%eax\n", invalid_param );
output( "\tjmp 2b\n" );
break;
case CPU_ARM:
@ -1861,10 +1856,6 @@ void output_syscalls( DLLSPEC *spec )
output_syscall_dispatcher( "_xsave" );
output_syscall_dispatcher( "_xsavec" );
break;
case CPU_x86_64:
output_syscall_dispatcher( "_xsave" );
output_syscall_dispatcher( "_xsavec" );
break;
default:
break;
}
@ -1881,6 +1872,9 @@ void output_syscalls( DLLSPEC *spec )
output( ".Lsyscall_args:\n" );
for (i = 0; i < count; i++)
output( "\t.byte %u\n", get_args_size( syscalls[i] ));
output( "\t.align %d\n", get_alignment(4) );
output( "%s\n", asm_globl("__wine_syscall_flags") );
output( "\t.long 0\n" );
return;
}