ntdll: Use the CPU area to get/set the Wow64 context on x86-64.
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
4acecd8619
commit
11d6c52f32
|
@ -1614,7 +1614,8 @@ void *get_native_context( CONTEXT *context )
|
||||||
*/
|
*/
|
||||||
void *get_wow_context( CONTEXT *context )
|
void *get_wow_context( CONTEXT *context )
|
||||||
{
|
{
|
||||||
return NULL;
|
if (context->SegCs != cs64_sel) return NULL;
|
||||||
|
return get_cpu_area( IMAGE_FILE_MACHINE_I386 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1851,10 +1852,97 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context )
|
||||||
*/
|
*/
|
||||||
NTSTATUS set_thread_wow64_context( HANDLE handle, const void *ctx, ULONG size )
|
NTSTATUS set_thread_wow64_context( HANDLE handle, const void *ctx, ULONG size )
|
||||||
{
|
{
|
||||||
BOOL self;
|
BOOL self = (handle == GetCurrentThread());
|
||||||
|
struct syscall_frame *frame = amd64_thread_data()->syscall_frame;
|
||||||
|
I386_CONTEXT *wow_frame;
|
||||||
|
const I386_CONTEXT *context = ctx;
|
||||||
|
DWORD flags = context->ContextFlags & ~CONTEXT_i386;
|
||||||
|
|
||||||
if (size != sizeof(I386_CONTEXT)) return STATUS_INFO_LENGTH_MISMATCH;
|
if (size != sizeof(I386_CONTEXT)) return STATUS_INFO_LENGTH_MISMATCH;
|
||||||
return set_thread_context( handle, ctx, &self, IMAGE_FILE_MACHINE_I386 );
|
|
||||||
|
/* debug registers require a server call */
|
||||||
|
if (self && (flags & CONTEXT_I386_DEBUG_REGISTERS))
|
||||||
|
self = (amd64_thread_data()->dr0 == context->Dr0 &&
|
||||||
|
amd64_thread_data()->dr1 == context->Dr1 &&
|
||||||
|
amd64_thread_data()->dr2 == context->Dr2 &&
|
||||||
|
amd64_thread_data()->dr3 == context->Dr3 &&
|
||||||
|
amd64_thread_data()->dr6 == context->Dr6 &&
|
||||||
|
amd64_thread_data()->dr7 == context->Dr7);
|
||||||
|
|
||||||
|
if (!self)
|
||||||
|
{
|
||||||
|
NTSTATUS ret = set_thread_context( handle, context, &self, IMAGE_FILE_MACHINE_I386 );
|
||||||
|
if (ret || !self) return ret;
|
||||||
|
if (flags & CONTEXT_I386_DEBUG_REGISTERS)
|
||||||
|
{
|
||||||
|
amd64_thread_data()->dr0 = context->Dr0;
|
||||||
|
amd64_thread_data()->dr1 = context->Dr1;
|
||||||
|
amd64_thread_data()->dr2 = context->Dr2;
|
||||||
|
amd64_thread_data()->dr3 = context->Dr3;
|
||||||
|
amd64_thread_data()->dr6 = context->Dr6;
|
||||||
|
amd64_thread_data()->dr7 = context->Dr7;
|
||||||
|
}
|
||||||
|
if (!(flags & ~CONTEXT_I386_DEBUG_REGISTERS)) return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(wow_frame = get_cpu_area( IMAGE_FILE_MACHINE_I386 ))) return STATUS_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
if (flags & CONTEXT_I386_INTEGER)
|
||||||
|
{
|
||||||
|
wow_frame->Eax = context->Eax;
|
||||||
|
wow_frame->Ebx = context->Ebx;
|
||||||
|
wow_frame->Ecx = context->Ecx;
|
||||||
|
wow_frame->Edx = context->Edx;
|
||||||
|
wow_frame->Esi = context->Esi;
|
||||||
|
wow_frame->Edi = context->Edi;
|
||||||
|
}
|
||||||
|
if (flags & CONTEXT_I386_CONTROL)
|
||||||
|
{
|
||||||
|
wow_frame->Esp = context->Esp;
|
||||||
|
wow_frame->Ebp = context->Ebp;
|
||||||
|
wow_frame->Eip = context->Eip;
|
||||||
|
wow_frame->EFlags = context->EFlags;
|
||||||
|
wow_frame->SegCs = cs32_sel;
|
||||||
|
wow_frame->SegSs = ds64_sel;
|
||||||
|
}
|
||||||
|
if (flags & CONTEXT_I386_SEGMENTS)
|
||||||
|
{
|
||||||
|
wow_frame->SegDs = ds64_sel;
|
||||||
|
wow_frame->SegEs = ds64_sel;
|
||||||
|
wow_frame->SegFs = 0; /* FIXME */
|
||||||
|
wow_frame->SegGs = ds64_sel;
|
||||||
|
}
|
||||||
|
if (flags & CONTEXT_I386_DEBUG_REGISTERS)
|
||||||
|
{
|
||||||
|
wow_frame->Dr0 = context->Dr0;
|
||||||
|
wow_frame->Dr1 = context->Dr1;
|
||||||
|
wow_frame->Dr2 = context->Dr2;
|
||||||
|
wow_frame->Dr3 = context->Dr3;
|
||||||
|
wow_frame->Dr6 = context->Dr6;
|
||||||
|
wow_frame->Dr7 = context->Dr7;
|
||||||
|
}
|
||||||
|
if (flags & CONTEXT_I386_EXTENDED_REGISTERS)
|
||||||
|
{
|
||||||
|
memcpy( &frame->xsave, context->ExtendedRegisters, sizeof(frame->xsave) );
|
||||||
|
}
|
||||||
|
else if (flags & CONTEXT_I386_FLOATING_POINT)
|
||||||
|
{
|
||||||
|
fpu_to_fpux( &frame->xsave, &context->FloatSave );
|
||||||
|
}
|
||||||
|
if (flags & CONTEXT_I386_XSTATE)
|
||||||
|
{
|
||||||
|
CONTEXT_EX *context_ex = (CONTEXT_EX *)(context + 1);
|
||||||
|
XSTATE *xs = (XSTATE *)((char *)context_ex + context_ex->XState.Offset);
|
||||||
|
|
||||||
|
if (xs->Mask & XSTATE_MASK_GSSE)
|
||||||
|
{
|
||||||
|
frame->xstate.Mask |= XSTATE_MASK_GSSE;
|
||||||
|
memcpy( &frame->xstate.YmmContext, &xs->YmmContext, sizeof(xs->YmmContext) );
|
||||||
|
}
|
||||||
|
else frame->xstate.Mask &= ~XSTATE_MASK_GSSE;
|
||||||
|
frame->restore_flags |= CONTEXT_I386_XSTATE;
|
||||||
|
}
|
||||||
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1863,10 +1951,96 @@ NTSTATUS set_thread_wow64_context( HANDLE handle, const void *ctx, ULONG size )
|
||||||
*/
|
*/
|
||||||
NTSTATUS get_thread_wow64_context( HANDLE handle, void *ctx, ULONG size )
|
NTSTATUS get_thread_wow64_context( HANDLE handle, void *ctx, ULONG size )
|
||||||
{
|
{
|
||||||
BOOL self;
|
DWORD needed_flags;
|
||||||
|
struct syscall_frame *frame = amd64_thread_data()->syscall_frame;
|
||||||
|
I386_CONTEXT *wow_frame, *context = ctx;
|
||||||
|
BOOL self = (handle == GetCurrentThread());
|
||||||
|
|
||||||
if (size != sizeof(I386_CONTEXT)) return STATUS_INFO_LENGTH_MISMATCH;
|
if (size != sizeof(I386_CONTEXT)) return STATUS_INFO_LENGTH_MISMATCH;
|
||||||
return get_thread_context( handle, ctx, &self, IMAGE_FILE_MACHINE_I386 );
|
|
||||||
|
needed_flags = context->ContextFlags & ~CONTEXT_i386;
|
||||||
|
|
||||||
|
/* debug registers require a server call */
|
||||||
|
if (needed_flags & CONTEXT_I386_DEBUG_REGISTERS) self = FALSE;
|
||||||
|
|
||||||
|
if (!self)
|
||||||
|
{
|
||||||
|
NTSTATUS ret = get_thread_context( handle, context, &self, IMAGE_FILE_MACHINE_I386 );
|
||||||
|
if (ret || !self) return ret;
|
||||||
|
/* update the cached version of the debug registers */
|
||||||
|
if (needed_flags & CONTEXT_I386_DEBUG_REGISTERS)
|
||||||
|
{
|
||||||
|
amd64_thread_data()->dr0 = context->Dr0;
|
||||||
|
amd64_thread_data()->dr1 = context->Dr1;
|
||||||
|
amd64_thread_data()->dr2 = context->Dr2;
|
||||||
|
amd64_thread_data()->dr3 = context->Dr3;
|
||||||
|
amd64_thread_data()->dr6 = context->Dr6;
|
||||||
|
amd64_thread_data()->dr7 = context->Dr7;
|
||||||
|
}
|
||||||
|
if (!(needed_flags & ~CONTEXT_I386_DEBUG_REGISTERS)) return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(wow_frame = get_cpu_area( IMAGE_FILE_MACHINE_I386 ))) return STATUS_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
if (needed_flags & CONTEXT_I386_INTEGER)
|
||||||
|
{
|
||||||
|
context->Eax = wow_frame->Eax;
|
||||||
|
context->Ebx = wow_frame->Ebx;
|
||||||
|
context->Ecx = wow_frame->Ecx;
|
||||||
|
context->Edx = wow_frame->Edx;
|
||||||
|
context->Esi = wow_frame->Esi;
|
||||||
|
context->Edi = wow_frame->Edi;
|
||||||
|
context->ContextFlags |= CONTEXT_I386_INTEGER;
|
||||||
|
}
|
||||||
|
if (needed_flags & CONTEXT_I386_CONTROL)
|
||||||
|
{
|
||||||
|
context->Esp = wow_frame->Esp;
|
||||||
|
context->Ebp = wow_frame->Ebp;
|
||||||
|
context->Eip = wow_frame->Eip;
|
||||||
|
context->EFlags = wow_frame->EFlags;
|
||||||
|
context->SegCs = wow_frame->SegCs;
|
||||||
|
context->SegSs = wow_frame->SegSs;
|
||||||
|
context->ContextFlags |= CONTEXT_I386_CONTROL;
|
||||||
|
}
|
||||||
|
if (needed_flags & CONTEXT_I386_SEGMENTS)
|
||||||
|
{
|
||||||
|
context->SegDs = wow_frame->SegDs;
|
||||||
|
context->SegEs = wow_frame->SegEs;
|
||||||
|
context->SegFs = wow_frame->SegFs;
|
||||||
|
context->SegGs = wow_frame->SegGs;
|
||||||
|
context->ContextFlags |= CONTEXT_I386_SEGMENTS;
|
||||||
|
}
|
||||||
|
if (needed_flags & CONTEXT_I386_EXTENDED_REGISTERS)
|
||||||
|
{
|
||||||
|
memcpy( context->ExtendedRegisters, &frame->xsave, sizeof(context->ExtendedRegisters) );
|
||||||
|
context->ContextFlags |= CONTEXT_I386_EXTENDED_REGISTERS;
|
||||||
|
}
|
||||||
|
if (needed_flags & CONTEXT_I386_FLOATING_POINT)
|
||||||
|
{
|
||||||
|
fpux_to_fpu( &context->FloatSave, &frame->xsave );
|
||||||
|
context->ContextFlags |= CONTEXT_I386_FLOATING_POINT;
|
||||||
|
}
|
||||||
|
if ((needed_flags & CONTEXT_I386_XSTATE) && (cpu_info.ProcessorFeatureBits & CPU_FEATURE_AVX))
|
||||||
|
{
|
||||||
|
CONTEXT_EX *context_ex = (CONTEXT_EX *)(context + 1);
|
||||||
|
XSTATE *xstate = (XSTATE *)((char *)context_ex + context_ex->XState.Offset);
|
||||||
|
unsigned int mask;
|
||||||
|
|
||||||
|
if (context_ex->XState.Length < offsetof(XSTATE, YmmContext) ||
|
||||||
|
context_ex->XState.Length > sizeof(XSTATE))
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
mask = (xstate_compaction_enabled ? xstate->CompactionMask : xstate->Mask) & XSTATE_MASK_GSSE;
|
||||||
|
xstate->Mask = frame->xstate.Mask & mask;
|
||||||
|
xstate->CompactionMask = xstate_compaction_enabled ? (0x8000000000000000 | mask) : 0;
|
||||||
|
memset( xstate->Reserved, 0, sizeof(xstate->Reserved) );
|
||||||
|
if (xstate->Mask)
|
||||||
|
{
|
||||||
|
if (context_ex->XState.Length < sizeof(XSTATE)) return STATUS_BUFFER_OVERFLOW;
|
||||||
|
memcpy( &xstate->YmmContext, &frame->xstate.YmmContext, sizeof(xstate->YmmContext) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue