ntdll: Only restore the modified parts of the syscall frame on i386.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2021-06-07 13:22:15 +02:00
parent 32f1bfd0f0
commit 050378d4d7
2 changed files with 85 additions and 132 deletions

View File

@ -481,25 +481,26 @@ C_ASSERT( sizeof(struct syscall_xsave) == 0x2c0 );
struct syscall_frame
{
DWORD eflags; /* 00 */
DWORD eip; /* 04 */
DWORD esp; /* 08 */
WORD cs; /* 0c */
WORD ss; /* 0e */
WORD ds; /* 10 */
WORD es; /* 12 */
WORD fs; /* 14 */
WORD gs; /* 16 */
DWORD eax; /* 18 */
DWORD ebx; /* 1c */
DWORD ecx; /* 20 */
DWORD edx; /* 24 */
DWORD edi; /* 28 */
DWORD esi; /* 2c */
DWORD ebp; /* 30 */
DWORD restore_flags; /* 00 */
DWORD eflags; /* 04 */
DWORD eip; /* 08 */
DWORD esp; /* 0c */
WORD cs; /* 10 */
WORD ss; /* 12 */
WORD ds; /* 14 */
WORD es; /* 16 */
WORD fs; /* 18 */
WORD gs; /* 1a */
DWORD eax; /* 1c */
DWORD ebx; /* 20 */
DWORD ecx; /* 24 */
DWORD edx; /* 28 */
DWORD edi; /* 2c */
DWORD esi; /* 30 */
DWORD ebp; /* 34 */
};
C_ASSERT( sizeof(struct syscall_frame) == 0x34 );
C_ASSERT( sizeof(struct syscall_frame) == 0x38 );
struct x86_thread_data
{
@ -902,63 +903,6 @@ static inline void restore_context( const struct xcontext *xcontext, ucontext_t
}
/***********************************************************************
* set_full_cpu_context
*
* Set the new CPU context.
*/
extern void set_full_cpu_context(void) DECLSPEC_HIDDEN;
__ASM_GLOBAL_FUNC( set_full_cpu_context,
"movl %fs:0x1f8,%ecx\n\t"
"movl $0,%fs:0x1f8\n\t" /* x86_thread_data()->syscall_frame = NULL */
"movw 0x16(%ecx),%gs\n\t" /* SegGs */
"movw 0x14(%ecx),%fs\n\t" /* SegFs */
"movw 0x12(%ecx),%es\n\t" /* SegEs */
"movl 0x1c(%ecx),%ebx\n\t" /* Ebx */
"movl 0x28(%ecx),%edi\n\t" /* Edi */
"movl 0x2c(%ecx),%esi\n\t" /* Esi */
"movl 0x30(%ecx),%ebp\n\t" /* Ebp */
"movw %ss,%ax\n\t"
"cmpw 0x0e(%ecx),%ax\n\t" /* SegSs */
"jne 1f\n\t"
/* As soon as we have switched stacks the context structure could
* be invalid (when signal handlers are executed for example). Copy
* values on the target stack before changing ESP. */
"movl 0x08(%ecx),%eax\n\t" /* Esp */
"leal -4*4(%eax),%eax\n\t"
"movl (%ecx),%edx\n\t" /* EFlags */
"movl %edx,3*4(%eax)\n\t"
"movl 0x0c(%ecx),%edx\n\t" /* SegCs */
"movl %edx,2*4(%eax)\n\t"
"movl 0x04(%ecx),%edx\n\t" /* Eip */
"movl %edx,1*4(%eax)\n\t"
"movl 0x18(%ecx),%edx\n\t" /* Eax */
"movl %edx,0*4(%eax)\n\t"
"pushl 0x10(%ecx)\n\t" /* SegDs */
"movl 0x24(%ecx),%edx\n\t" /* Edx */
"movl 0x20(%ecx),%ecx\n\t" /* Ecx */
"popl %ds\n\t"
"movl %eax,%esp\n\t"
"popl %eax\n\t"
"iret\n"
/* Restore the context when the stack segment changes. We can't use
* the same code as above because we do not know if the stack segment
* is 16 or 32 bit, and 'movl' will throw an exception when we try to
* access memory above the limit. */
"1:\n\t"
"movl 0x24(%ecx),%edx\n\t" /* Edx */
"movl 0x18(%ecx),%eax\n\t" /* Eax */
"movw 0x0e(%ecx),%ss\n\t" /* SegSs */
"movl 0x08(%ecx),%esp\n\t" /* Esp */
"pushl 0x00(%ecx)\n\t" /* EFlags */
"pushl 0x0c(%ecx)\n\t" /* SegCs */
"pushl 0x04(%ecx)\n\t" /* Eip */
"pushl 0x10(%ecx)\n\t" /* SegDs */
"movl 0x20(%ecx),%ecx\n\t" /* Ecx */
"popl %ds\n\t"
"iret" )
/***********************************************************************
* signal_restore_full_cpu_context
*
@ -966,21 +910,7 @@ __ASM_GLOBAL_FUNC( set_full_cpu_context,
*/
void signal_restore_full_cpu_context(void)
{
struct syscall_xsave *xsave = get_syscall_xsave( x86_thread_data()->syscall_frame );
if (cpu_info.ProcessorFeatureBits & CPU_FEATURE_XSAVE)
{
__asm__ volatile( "xrstor %0" : : "m"(*xsave), "a" (7), "d" (0) );
}
else if (cpu_info.ProcessorFeatureBits & CPU_FEATURE_FXSR)
{
__asm__ volatile( "fxrstor %0" : : "m"(xsave->u.xsave) );
}
else
{
__asm__ volatile( "frstor %0; fwait" : : "m" (xsave->u.fsave) );
}
set_full_cpu_context();
x86_thread_data()->syscall_frame->restore_flags |= CONTEXT_INTEGER;
}
@ -1092,6 +1022,7 @@ NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context )
else xsave->xstate.mask &= ~XSTATE_MASK_GSSE;
}
frame->restore_flags |= flags & ~CONTEXT_INTEGER;
return STATUS_SUCCESS;
}
@ -1660,7 +1591,7 @@ __ASM_GLOBAL_FUNC( call_user_apc_dispatcher,
"movl 0xc4(%esi),%eax\n\t" /* context_ptr->Esp */
"jmp 2f\n\t"
"1:\tmovl %fs:0x1f8,%eax\n\t" /* x86_thread_data()->syscall_frame */
"leal 0x38(%eax),%eax\n\t" /* &x86_thread_data()->syscall_frame->ret_addr */
"leal 0x3c(%eax),%eax\n\t" /* &x86_thread_data()->syscall_frame->ret_addr */
"2:\tsubl $0x2e0,%eax\n\t" /* sizeof(struct apc_stack_layout) */
"movl %ebp,%esp\n\t" /* pop return address */
"cmpl %esp,%eax\n\t"
@ -1700,15 +1631,15 @@ __ASM_GLOBAL_FUNC( call_user_exception_dispatcher,
"jne 1f\n\t"
"decl 0xb8(%ecx)\n" /* context->Eip */
"1:\tmovl %fs:0x1f8,%eax\n\t" /* x86_thread_data()->syscall_frame */
"movl 0x1c(%eax),%ebx\n\t" /* frame->ebx */
"movl 0x28(%eax),%edi\n\t" /* frame->edi */
"movl 0x2c(%eax),%esi\n\t" /* frame->esi */
"movl 0x30(%eax),%ebp\n\t" /* frame->ebp */
"movl %edx,0x30(%eax)\n\t"
"movl %ecx,0x34(%eax)\n\t"
"movl 0x20(%eax),%ebx\n\t" /* frame->ebx */
"movl 0x2c(%eax),%edi\n\t" /* frame->edi */
"movl 0x30(%eax),%esi\n\t" /* frame->esi */
"movl 0x34(%eax),%ebp\n\t" /* frame->ebp */
"movl %edx,0x34(%eax)\n\t"
"movl %ecx,0x38(%eax)\n\t"
"movl 12(%esp),%edx\n\t" /* dispatcher */
"movl $0,%fs:0x1f8\n\t"
"leal 0x30(%eax),%esp\n\t"
"leal 0x34(%eax),%esp\n\t"
"jmp *%edx" )
/**********************************************************************

View File

@ -1446,6 +1446,7 @@ static void output_syscall_dispatcher(void)
output( "\tmovl %%esi,-0x04(%%ebp)\n" );
output_cfi( ".cfi_rel_offset %%esi,-0x04\n" );
output( "\tpushfl\n" );
output( "\tpushl $0\n" );
output( "\tmovw %%gs,-0x1a(%%ebp)\n" );
output( "\tmovw %%fs,-0x1c(%%ebp)\n" );
output( "\tmovw %%es,-0x1e(%%ebp)\n" );
@ -1496,7 +1497,7 @@ static void output_syscall_dispatcher(void)
output( "\tjmp 4f\n" );
output( "3:\tfnsave (%%esp)\n" );
output( "\tfwait\n" );
output( "4:\tleal -0x30(%%ebp),%%ecx\n" );
output( "4:\tleal -0x34(%%ebp),%%ecx\n" );
output( "\tmovl %%ecx,%%fs:0x1f8\n" ); /* x86_thread_data()->syscall_frame */
output( "\tcmpl 8(%%ebx),%%edx\n" ); /* table->ServiceLimit */
output( "\tjae 6f\n" );
@ -1514,15 +1515,18 @@ static void output_syscall_dispatcher(void)
output( "\tmovl %%ebx,%%esi\n" );
output( "\tcall *(%%eax,%%edx,4)\n" );
output( "5:\tmovl $0,%%fs:0x1f8\n" );
output( "\tleal -0x2f0(%%ebp),%%ebx\n") ;
output( "\tmovl -0x34(%%ebp),%%ecx\n" ); /* syscall_frame->restore_flags */
output( "\ttestl $0x68,%%ecx\n" ); /* CONTEXT_FLOATING_POINT | CONTEXT_EXTENDED_REGISTERS | CONTEXT_XSAVE */
output( "\tjz 3f\n" );
output( "\tleal -0x2f4(%%ebp),%%ebx\n") ;
output( "\tandl $~63,%%ebx\n" );
output( "\ttestl $3,%%esi\n" ); /* SYSCALL_HAVE_XSAVE | SYSCALL_HAVE_XSAVEC */
output( "\tjz 1f\n" );
output( "\tmovl %%eax,%%ecx\n" );
output( "\tmovl %%eax,%%edi\n" );
output( "\tmovl $7,%%eax\n" );
output( "\txorl %%edx,%%edx\n" );
output( "\txrstor (%%ebx)\n" );
output( "\tmovl %%ecx,%%eax\n" );
output( "\tmovl %%edi,%%eax\n" );
output( "\tjmp 3f\n" );
output( "1:\ttestl $4,%%esi\n" ); /* SYSCALL_HAVE_FXSAVE */
output( "\tjz 2f\n" );
@ -1530,51 +1534,69 @@ static void output_syscall_dispatcher(void)
output( "\tjmp 3f\n" );
output( "2:\tfrstor (%%ebx)\n" );
output( "\tfwait\n" );
output( "3:\tleal -0x30(%%ebp),%%ebx\n" );
output_cfi( ".cfi_def_cfa_register %%ebx" );
output_cfi( ".cfi_adjust_cfa_offset 0x30\n" );
output( "\tmovl %%eax,0x18(%%ebx)\n" );
output( "\tmovw 0x16(%%ebx),%%gs\n" );
output( "\tmovw 0x14(%%ebx),%%fs\n" );
output( "\tmovw 0x12(%%ebx),%%es\n" );
output( "\tmovl 0x28(%%ebx),%%edi\n" );
output( "3:\tmovl -0x08(%%ebp),%%edi\n" );
output_cfi( ".cfi_same_value %%edi" );
output( "\tmovl 0x2c(%%ebx),%%esi\n" );
output( "\tmovl -0x04(%%ebp),%%esi\n" );
output_cfi( ".cfi_same_value %%esi" );
output( "\tmovl -0x14(%%ebp),%%ebx\n" );
output_cfi( ".cfi_same_value %%ebx" );
output( "\ttestl $0x7,%%ecx\n" ); /* CONTEXT_CONTROL | CONTEXT_SEGMENTS | CONTEXT_INTEGER */
output( "\tjnz 1f\n" );
output( "\tmovl -0x2c(%%ebp),%%ecx\n" ); /* frame->eip */
output( "\tleal -0x28(%%ebp),%%esp\n" ); /* frame->esp */
output( "\tmovl (%%ebp),%%ebp\n" );
output_cfi( ".cfi_same_value %%ebp" );
output( "\tmovw %%ss,%%cx\n" );
output( "\tcmpw 0x0e(%%ebx),%%cx\n" );
output( "\tpopl %%esp\n" );
output( "\tjmpl *%%ecx\n" );
output( "1:\ttestl $0x2,%%ecx\n" ); /* CONTEXT_INTEGER */
output( "\tjnz 1f\n" );
output( "\tmovl %%eax,-0x18(%%ebp)\n" );
output( "\tmovl $0,-0x10(%%ebp)\n" );
output( "\tmovl $0,-0x0c(%%ebp)\n" );
output( "1:\tmovw -0x1a(%%ebp),%%gs\n" );
output( "\tmovw -0x1c(%%ebp),%%fs\n" );
output( "\tmovw -0x1e(%%ebp),%%es\n" );
output( "\tleal -0x34(%%ebp),%%ecx\n" );
output_cfi( ".cfi_def_cfa_register %%ecx" );
output_cfi( ".cfi_adjust_cfa_offset 0x34\n" );
output( "\tmovl (%%ebp),%%ebp\n" );
output_cfi( ".cfi_same_value %%ebp" );
output( "\tmovw %%ss,%%ax\n" );
output( "\tcmpw 0x12(%%ecx),%%ax\n" );
output( "\tjne 3f\n" );
/* As soon as we have switched stacks the context structure could
* be invalid (when signal handlers are executed for example). Copy
* values on the target stack before changing ESP. */
output( "\tmovl 0x08(%%ebx),%%ecx\n" );
output( "\tleal -3*4(%%ecx),%%ecx\n" );
output( "\tmovl (%%ebx),%%edx\n" );
output( "\tmovl %%edx,2*4(%%ecx)\n" );
output( "\tmovl 0x0c(%%ebx),%%edx\n" );
output( "\tmovl %%edx,1*4(%%ecx)\n" );
output( "\tmovl 0x04(%%ebx),%%edx\n" );
output( "\tmovl %%edx,0*4(%%ecx)\n" );
output( "\tpushl 0x10(%%ebx)\n" );
output( "\tmovl 0x1c(%%ebx),%%ebx\n" );
output_cfi( ".cfi_same_value %%ebx" );
output( "\tmovl 0x0c(%%ecx),%%eax\n" );
output( "\tleal -4*4(%%eax),%%eax\n" );
output( "\tmovl 0x04(%%ecx),%%edx\n" );
output( "\tmovl %%edx,3*4(%%eax)\n" );
output( "\tmovl 0x10(%%ecx),%%edx\n" );
output( "\tmovl %%edx,2*4(%%eax)\n" );
output( "\tmovl 0x08(%%ecx),%%edx\n" );
output( "\tmovl %%edx,1*4(%%eax)\n" );
output( "\tmovl 0x1c(%%ecx),%%edx\n" );
output( "\tmovl %%edx,0*4(%%eax)\n" );
output( "\tpushl 0x14(%%ecx)\n" );
output( "\tmovl 0x28(%%ecx),%%edx\n" );
output( "\tmovl 0x24(%%ecx),%%ecx\n" );
output( "\tpopl %%ds\n" );
output( "\tmovl %%ecx,%%esp\n" );
output( "\tmovl %%eax,%%esp\n" );
output( "\tpopl %%eax\n" );
output( "\tiret\n" );
/* Restore the context when the stack segment changes. We can't use
* the same code as above because we do not know if the stack segment
* is 16 or 32 bit, and 'movl' will throw an exception when we try to
* access memory above the limit. */
output( "\t3:\tmovl 0x18(%%ebx),%%ecx\n" );
output( "\tmovw 0x0e(%%ebx),%%ss\n" );
output( "\tmovl 0x08(%%ebx),%%esp\n" );
output( "\tpushl 0x00(%%ebx)\n" );
output( "\tpushl 0x0c(%%ebx)\n" );
output( "\tpushl 0x04(%%ebx)\n" );
output( "\tpushl 0x10(%%ebx)\n" );
output( "\tmovl 0x1c(%%ebx),%%ebx\n" );
output( "3:\tmovl 0x28(%%ecx),%%edx\n" );
output( "\tmovl 0x1c(%%ecx),%%eax\n" );
output( "\tmovw 0x12(%%ecx),%%ss\n" );
output( "\tmovl 0x0c(%%ecx),%%esp\n" );
output( "\tpushl 0x04(%%ecx)\n" );
output( "\tpushl 0x10(%%ecx)\n" );
output( "\tpushl 0x08(%%ecx)\n" );
output( "\tpushl 0x14(%%ecx)\n" );
output( "\tmovl 0x24(%%ecx),%%ecx\n" );
output( "\tpopl %%ds\n" );
output( "\tiret\n" );
output( "6:\tmovl $0x%x,%%eax\n", invalid_param );