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