Jacek Caban : ntdll: Use syscall frames in x86_64 NtSetContextThread implementation.
Alexandre Julliard
julliard at winehq.org
Mon Feb 22 15:43:22 CST 2021
Module: wine
Branch: master
Commit: 3ecd43dc6fabe072857139d513ae8e3a44861662
URL: https://source.winehq.org/git/wine.git/?a=commit;h=3ecd43dc6fabe072857139d513ae8e3a44861662
Author: Jacek Caban <jacek at codeweavers.com>
Date: Mon Feb 22 18:01:47 2021 +0100
ntdll: Use syscall frames in x86_64 NtSetContextThread implementation.
Signed-off-by: Jacek Caban <jacek at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
dlls/ntdll/unix/signal_x86_64.c | 163 ++++++++++++++++++++++++----------------
1 file changed, 97 insertions(+), 66 deletions(-)
diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c
index 8d3353e959d..b5040852cbe 100644
--- a/dlls/ntdll/unix/signal_x86_64.c
+++ b/dlls/ntdll/unix/signal_x86_64.c
@@ -1568,71 +1568,47 @@ static void restore_context( const struct xcontext *xcontext, ucontext_t *sigcon
*
* Set the new CPU context.
*/
-extern void set_full_cpu_context( const CONTEXT *context );
+extern void set_full_cpu_context(void);
__ASM_GLOBAL_FUNC( set_full_cpu_context,
- "subq $40,%rsp\n\t"
- __ASM_SEH(".seh_stackalloc 0x40\n\t")
- __ASM_SEH(".seh_endprologue\n\t")
- __ASM_CFI(".cfi_adjust_cfa_offset 40\n\t")
"movq %gs:0x30,%rdx\n\t"
- "movw 0x38(%rdi),%ax\n\t" /* context->SegCs */
- "movq %rax,8(%rsp)\n\t"
- "movw 0x42(%rdi),%ax\n\t" /* context->SegSs */
- "movq %rax,32(%rsp)\n\t"
- "movq 0x44(%rdi),%rax\n\t" /* context->Eflags */
- "movq %rax,16(%rsp)\n\t"
- "movq $0,0x328(%rdx)\n\t" /* amd64_thread_data()->syscall_frame */
- "movq 0x80(%rdi),%rcx\n\t" /* context->Rcx */
- "movq 0x88(%rdi),%rdx\n\t" /* context->Rdx */
- "movq 0x90(%rdi),%rbx\n\t" /* context->Rbx */
- "movq 0x98(%rdi),%rax\n\t" /* context->Rsp */
- "movq %rax,24(%rsp)\n\t"
- "movq 0xa0(%rdi),%rbp\n\t" /* context->Rbp */
- "movq 0xa8(%rdi),%rsi\n\t" /* context->Rsi */
- "movq 0xb8(%rdi),%r8\n\t" /* context->R8 */
- "movq 0xc0(%rdi),%r9\n\t" /* context->R9 */
- "movq 0xc8(%rdi),%r10\n\t" /* context->R10 */
- "movq 0xd0(%rdi),%r11\n\t" /* context->R11 */
- "movq 0xd8(%rdi),%r12\n\t" /* context->R12 */
- "movq 0xe0(%rdi),%r13\n\t" /* context->R13 */
- "movq 0xe8(%rdi),%r14\n\t" /* context->R14 */
- "movq 0xf0(%rdi),%r15\n\t" /* context->R15 */
- "movq 0xf8(%rdi),%rax\n\t" /* context->Rip */
- "movq %rax,(%rsp)\n\t"
- "fxrstor 0x100(%rdi)\n\t" /* context->FltSave */
- "movq 0x78(%rdi),%rax\n\t" /* context->Rax */
- "movq 0xb0(%rdi),%rdi\n\t" /* context->Rdi */
- "iretq" );
-
-
-/***********************************************************************
- * restore_xstate
- *
- * Restore the XState context.
- */
-static void restore_xstate( const CONTEXT *context )
-{
- XSAVE_FORMAT *xrstor_base;
- XSTATE *xs;
-
- if (!(user_shared_data->XState.EnabledFeatures && (xs = xstate_from_context( context ))))
- return;
-
- xrstor_base = (XSAVE_FORMAT *)xs - 1;
+ "movq 0x328(%rdx),%rsp\n\t" /* amd64_thread_data()->syscall_frame */
+ "movq $0,0x328(%rdx)\n\t"
+ "movq 0x00(%rsp),%rax\n\t"
+ "movq 0x08(%rsp),%rbx\n\t"
+ "movq 0x10(%rsp),%rcx\n\t"
+ "movq 0x18(%rsp),%rdx\n\t"
+ "movq 0x20(%rsp),%rsi\n\t"
+ "movq 0x28(%rsp),%rdi\n\t"
+ "movq 0x30(%rsp),%r8\n\t"
+ "movq 0x38(%rsp),%r9\n\t"
+ "movq 0x40(%rsp),%r10\n\t"
+ "movq 0x48(%rsp),%r11\n\t"
+ "movq 0x50(%rsp),%r12\n\t"
+ "movq 0x58(%rsp),%r13\n\t"
+ "movq 0x60(%rsp),%r14\n\t"
+ "movq 0x68(%rsp),%r15\n\t"
+ "movq 0x98(%rsp),%rbp\n\t"
+ "leaq 0x70(%rsp),%rsp\n\t"
+ "iretq" )
+
+static void signal_restore_full_cpu_context(void)
+{
+ struct syscall_xsave *xsave = get_syscall_xsave( get_syscall_frame() );
+ SYSTEM_CPU_INFORMATION cpu_info;
- if (!(xs->CompactionMask & ((ULONG64)1 << 63)))
+ NtQuerySystemInformation( SystemCpuInformation, &cpu_info, sizeof(cpu_info), NULL );
+ if (cpu_info.FeatureSet & CPU_FEATURE_XSAVE)
{
- /* Non-compacted xrstor will load Mxcsr regardless of the specified mask. Loading garbage there
- * may lead to fault. We have only padding, no more used EXCEPTION_RECORD or unused context fields
- * at the MxCsr restore location, so just put it there. */
- assert( (void *)&xrstor_base->MxCsr > (void *)context->VectorRegister );
- xrstor_base->MxCsr = context->u.FltSave.MxCsr;
- xrstor_base->MxCsr_Mask = context->u.FltSave.MxCsr_Mask;
+ __asm__ volatile( "xrstor64 %0" : : "m"(xsave->xsave), "a" (7), "d" (0) );
}
-
- __asm__ volatile( "xrstor64 %0" : : "m"(*xrstor_base), "a" (4), "d" (0) );
+ else
+ {
+ __asm__ volatile( "fxrstor64 %0" : : "m"(xsave->xsave) );
+ }
+ set_full_cpu_context();
}
+
/***********************************************************************
* get_server_context_flags
*
@@ -1798,6 +1774,9 @@ NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context )
NTSTATUS ret = STATUS_SUCCESS;
DWORD flags = context->ContextFlags & ~CONTEXT_AMD64;
BOOL self = (handle == GetCurrentThread());
+ struct syscall_frame *frame;
+ struct syscall_xsave *xsave;
+ XSTATE *xs;
/* debug registers require a server call */
if (self && (flags & CONTEXT_DEBUG_REGISTERS))
@@ -1826,16 +1805,68 @@ NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context )
}
}
- restore_xstate( context );
-
- if (flags & CONTEXT_FULL)
+ frame = amd64_thread_data()->syscall_frame;
+ xsave = get_syscall_xsave( frame );
+ if (flags & CONTEXT_INTEGER)
{
- if (!(flags & CONTEXT_CONTROL))
- FIXME( "setting partial context (%x) not supported\n", flags );
- else
- set_full_cpu_context( context );
+ frame->rax = context->Rax;
+ frame->rbx = context->Rbx;
+ frame->rcx = context->Rcx;
+ frame->rdx = context->Rdx;
+ frame->rsi = context->Rsi;
+ frame->rdi = context->Rdi;
+ frame->r8 = context->R8;
+ frame->r9 = context->R9;
+ frame->r10 = context->R10;
+ frame->r11 = context->R11;
+ frame->r12 = context->R12;
+ frame->r13 = context->R13;
+ frame->r14 = context->R14;
+ frame->r15 = context->R15;
}
- return ret;
+ if (flags & CONTEXT_CONTROL)
+ {
+ frame->rsp = context->Rsp;
+ frame->rbp = context->Rbp;
+ frame->rip = context->Rip;
+ frame->eflags = context->EFlags;
+ frame->cs = context->SegCs;
+ frame->ss = context->SegSs;
+ }
+ if (flags & CONTEXT_SEGMENTS)
+ {
+ frame->ds = context->SegDs;
+ frame->es = context->SegEs;
+ frame->fs = context->SegFs;
+ frame->gs = context->SegGs;
+ }
+ if (flags & CONTEXT_FLOATING_POINT)
+ {
+ xsave->xsave = context->u.FltSave;
+ }
+ if (user_shared_data->XState.EnabledFeatures && (xs = xstate_from_context( context )))
+ {
+ CONTEXT_EX *context_ex = (CONTEXT_EX *)(context + 1);
+
+ if (context_ex->XState.Length < offsetof(XSTATE, YmmContext)
+ || context_ex->XState.Length > sizeof(XSTATE))
+ return STATUS_INVALID_PARAMETER;
+
+ if (xs->Mask & XSTATE_MASK_GSSE)
+ {
+ if (context_ex->XState.Length < sizeof(XSTATE))
+ return STATUS_BUFFER_OVERFLOW;
+
+ xsave->xstate.Mask |= XSTATE_MASK_GSSE;
+ memcpy( &xsave->xstate.YmmContext, &xs->YmmContext, sizeof(xs->YmmContext) );
+ }
+ else if (xs->CompactionMask & XSTATE_MASK_GSSE)
+ xsave->xstate.Mask &= ~XSTATE_MASK_GSSE;
+ }
+
+ if (!(flags & CONTEXT_INTEGER)) frame->rax = STATUS_SUCCESS;
+ signal_restore_full_cpu_context();
+ return STATUS_SUCCESS;
}
More information about the wine-cvs
mailing list