[PATCH 0/3] MR5094: ntdll: Support generic xstate (part 2).
From: Paul Gofman <pgofman(a)codeweavers.com> --- dlls/ntdll/unix/signal_i386.c | 17 ++--------------- dlls/ntdll/unix/signal_x86_64.c | 5 ----- dlls/ntdll/unix/thread.c | 8 ++++---- 3 files changed, 6 insertions(+), 24 deletions(-) diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c index 93bcf607f41..1439ee7df97 100644 --- a/dlls/ntdll/unix/signal_i386.c +++ b/dlls/ntdll/unix/signal_i386.c @@ -607,7 +607,6 @@ struct xcontext { CONTEXT c; CONTEXT_EX c_ex; - ULONG64 host_compaction_mask; }; static inline XSAVE_AREA_HEADER *xstate_from_context( const CONTEXT *context ) @@ -831,11 +830,7 @@ static inline void save_context( struct xcontext *xcontext, const ucontext_t *si context->ContextFlags |= CONTEXT_FLOATING_POINT | CONTEXT_EXTENDED_REGISTERS; memcpy( context->ExtendedRegisters, fpux, sizeof(*fpux) ); if (!fpu) fpux_to_fpu( &context->FloatSave, fpux ); - if (xstate_extended_features() && (xs = XState_sig(fpux))) - { - context_init_xstate( context, xs ); - xcontext->host_compaction_mask = xs->CompactionMask; - } + if (xstate_extended_features() && (xs = XState_sig(fpux))) context_init_xstate( context, xs ); } if (!fpu && !fpux) save_fpu( context ); } @@ -876,15 +871,7 @@ static inline void restore_context( const struct xcontext *xcontext, ucontext_t SS_sig(sigcontext) = context->SegSs; if (fpu) *fpu = context->FloatSave; - if (fpux) - { - XSAVE_AREA_HEADER *xs; - - memcpy( fpux, context->ExtendedRegisters, sizeof(*fpux) ); - - if (xstate_extended_features() && (xs = XState_sig(fpux))) - xs->CompactionMask = xcontext->host_compaction_mask; - } + if (fpux) memcpy( fpux, context->ExtendedRegisters, sizeof(*fpux) ); if (!fpu && !fpux) restore_fpu( context ); } diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index 501ae14cae5..fc5add7c432 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -479,7 +479,6 @@ struct xcontext { CONTEXT c; CONTEXT_EX c_ex; - ULONG64 host_compaction_mask; }; static inline XSAVE_AREA_HEADER *xstate_from_context( const CONTEXT *context ) @@ -907,7 +906,6 @@ static void save_context( struct xcontext *xcontext, const ucontext_t *sigcontex * just reference sigcontext without overflowing 32 bit XState.Offset */ context_init_xstate( context, xs ); assert( xcontext->c_ex.XState.Offset == (BYTE *)xs - (BYTE *)&xcontext->c_ex ); - xcontext->host_compaction_mask = xs->CompactionMask; } } } @@ -921,7 +919,6 @@ static void save_context( struct xcontext *xcontext, const ucontext_t *sigcontex static void restore_context( const struct xcontext *xcontext, ucontext_t *sigcontext ) { const CONTEXT *context = &xcontext->c; - XSAVE_AREA_HEADER *xs; amd64_thread_data()->dr0 = context->Dr0; amd64_thread_data()->dr1 = context->Dr1; @@ -931,8 +928,6 @@ static void restore_context( const struct xcontext *xcontext, ucontext_t *sigcon amd64_thread_data()->dr7 = context->Dr7; set_sigcontext( context, sigcontext ); if (FPU_sig(sigcontext)) *FPU_sig(sigcontext) = context->FltSave; - if (xstate_extended_features() && (xs = XState_sig(FPU_sig(sigcontext)))) - xs->CompactionMask = xcontext->host_compaction_mask; leave_handler( sigcontext ); } diff --git a/dlls/ntdll/unix/thread.c b/dlls/ntdll/unix/thread.c index 52cb0f26e97..bd1fbcdbfc2 100644 --- a/dlls/ntdll/unix/thread.c +++ b/dlls/ntdll/unix/thread.c @@ -688,7 +688,7 @@ static NTSTATUS context_from_server( void *dst, const context_t *from, USHORT ma XSTATE *xs = (XSTATE *)((char *)xctx + xctx->XState.Offset); xs->Mask &= ~4; - if (user_shared_data->XState.CompactionEnabled) xs->CompactionMask = 0x8000000000000004; + if (xs->CompactionMask) xs->CompactionMask = 0x8000000000000004; for (i = 0; i < ARRAY_SIZE( from->ymm.regs.ymm_high); i++) { if (!from->ymm.regs.ymm_high[i].low && !from->ymm.regs.ymm_high[i].high) continue; @@ -762,7 +762,7 @@ static NTSTATUS context_from_server( void *dst, const context_t *from, USHORT ma XSTATE *xs = (XSTATE *)((char *)xctx + xctx->XState.Offset); xs->Mask &= ~4; - if (user_shared_data->XState.CompactionEnabled) xs->CompactionMask = 0x8000000000000004; + if (xs->CompactionMask) xs->CompactionMask = 0x8000000000000004; for (i = 0; i < ARRAY_SIZE( from->ymm.regs.ymm_high); i++) { if (!from->ymm.regs.ymm_high[i].low && !from->ymm.regs.ymm_high[i].high) continue; @@ -837,7 +837,7 @@ static NTSTATUS context_from_server( void *dst, const context_t *from, USHORT ma XSTATE *xs = (XSTATE *)((char *)xctx + xctx->XState.Offset); xs->Mask &= ~4; - if (user_shared_data->XState.CompactionEnabled) xs->CompactionMask = 0x8000000000000004; + if (xs->CompactionMask) xs->CompactionMask = 0x8000000000000004; for (i = 0; i < ARRAY_SIZE( from->ymm.regs.ymm_high); i++) { if (!from->ymm.regs.ymm_high[i].low && !from->ymm.regs.ymm_high[i].high) continue; @@ -919,7 +919,7 @@ static NTSTATUS context_from_server( void *dst, const context_t *from, USHORT ma XSTATE *xs = (XSTATE *)((char *)xctx + xctx->XState.Offset); xs->Mask &= ~4; - if (user_shared_data->XState.CompactionEnabled) xs->CompactionMask = 0x8000000000000004; + if (xs->CompactionMask) xs->CompactionMask = 0x8000000000000004; for (i = 0; i < ARRAY_SIZE( from->ymm.regs.ymm_high); i++) { if (!from->ymm.regs.ymm_high[i].low && !from->ymm.regs.ymm_high[i].high) continue; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/5094
From: Paul Gofman <pgofman(a)codeweavers.com> --- dlls/ntdll/unix/signal_i386.c | 44 ++++++++++++++++++++++++--------- dlls/ntdll/unix/signal_x86_64.c | 34 +++++++++++++++++++------ 2 files changed, 60 insertions(+), 18 deletions(-) diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c index 1439ee7df97..2a89798c7ec 100644 --- a/dlls/ntdll/unix/signal_i386.c +++ b/dlls/ntdll/unix/signal_i386.c @@ -2107,24 +2107,46 @@ static void quit_handler( int signal, siginfo_t *siginfo, void *sigcontext ) */ static void usr1_handler( int signal, siginfo_t *siginfo, void *sigcontext ) { - struct xcontext xcontext; + ucontext_t *ucontext = sigcontext; init_handler( sigcontext ); - if (is_inside_syscall( sigcontext )) + + if (is_inside_syscall( ucontext )) { - DECLSPEC_ALIGN(64) XSTATE xs; - xcontext.c.ContextFlags = CONTEXT_FULL; - context_init_xstate( &xcontext.c, &xs ); + struct syscall_frame *frame = x86_thread_data()->syscall_frame; + ULONG64 saved_compaction = 0; + struct xcontext *context; - NtGetContextThread( GetCurrentThread(), &xcontext.c ); - wait_suspend( &xcontext.c ); - NtSetContextThread( GetCurrentThread(), &xcontext.c ); + context = (struct xcontext *)(((ULONG_PTR)ESP_sig(ucontext) - sizeof(*context)) & ~15); + if ((char *)context < (char *)ntdll_get_thread_data()->kernel_stack) + { + ERR_(seh)( "kernel stack overflow.\n" ); + return; + } + context->c.ContextFlags = CONTEXT_FULL; + NtGetContextThread( GetCurrentThread(), &context->c ); + if (xstate_extended_features()) + { + context_init_xstate( &context->c, &frame->xstate ); + saved_compaction = frame->xstate.CompactionMask; + } + wait_suspend( &context->c ); + if (xstate_extended_features()) frame->xstate.CompactionMask = saved_compaction; + if (context->c.ContextFlags & 0x40) + { + /* xstate is updated directly in frame's xstate */ + context->c.ContextFlags &= ~0x40; + frame->restore_flags |= 0x40; + } + NtSetContextThread( GetCurrentThread(), &context->c ); } else { - save_context( &xcontext, sigcontext ); - wait_suspend( &xcontext.c ); - restore_context( &xcontext, sigcontext ); + struct xcontext context; + + save_context( &context, ucontext ); + wait_suspend( &context.c ); + restore_context( &context, ucontext ); } } diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index fc5add7c432..0da0006b216 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -2155,20 +2155,40 @@ static void quit_handler( int signal, siginfo_t *siginfo, void *sigcontext ) static void usr1_handler( int signal, siginfo_t *siginfo, void *sigcontext ) { ucontext_t *ucontext = init_handler( sigcontext ); - struct xcontext context; if (is_inside_syscall( ucontext )) { - DECLSPEC_ALIGN(64) XSTATE xs; - context.c.ContextFlags = CONTEXT_FULL | CONTEXT_SEGMENTS; - context_init_xstate( &context.c, &xs ); + struct syscall_frame *frame = amd64_thread_data()->syscall_frame; + ULONG64 saved_compaction = 0; + struct xcontext *context; - NtGetContextThread( GetCurrentThread(), &context.c ); - wait_suspend( &context.c ); - NtSetContextThread( GetCurrentThread(), &context.c ); + context = (struct xcontext *)(((ULONG_PTR)RSP_sig(ucontext) - sizeof(*context)) & ~15); + if ((char *)context < (char *)ntdll_get_thread_data()->kernel_stack) + { + ERR_(seh)( "kernel stack overflow.\n" ); + return; + } + context->c.ContextFlags = CONTEXT_FULL | CONTEXT_SEGMENTS; + NtGetContextThread( GetCurrentThread(), &context->c ); + if (xstate_extended_features()) + { + context_init_xstate( &context->c, &frame->xstate ); + saved_compaction = frame->xstate.CompactionMask; + } + wait_suspend( &context->c ); + if (xstate_extended_features()) frame->xstate.CompactionMask = saved_compaction; + if (context->c.ContextFlags & 0x40) + { + /* xstate is updated directly in frame's xstate */ + context->c.ContextFlags &= ~0x40; + frame->restore_flags |= 0x40; + } + NtSetContextThread( GetCurrentThread(), &context->c ); } else { + struct xcontext context; + save_context( &context, ucontext ); wait_suspend( &context.c ); restore_context( &context, ucontext ); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/5094
From: Paul Gofman <pgofman(a)codeweavers.com> --- dlls/ntdll/exception.c | 121 ++++++++++++++++++++++++++++++++++------- 1 file changed, 102 insertions(+), 19 deletions(-) diff --git a/dlls/ntdll/exception.c b/dlls/ntdll/exception.c index a4c5a770b05..1f5c0a7eca6 100644 --- a/dlls/ntdll/exception.c +++ b/dlls/ntdll/exception.c @@ -514,6 +514,52 @@ static const struct context_parameters *context_get_parameters( ULONG context_fl return NULL; } +/* offset is from the start of XSAVE_AREA_HEADER. */ +static int next_compacted_xstate_offset( int off, UINT64 compaction_mask, int feature_idx ) +{ + const UINT64 feature_mask = (UINT64)1 << feature_idx; + + if (compaction_mask & feature_mask) off += user_shared_data->XState.Features[feature_idx].Size; + if (user_shared_data->XState.AlignedFeatures & (feature_mask << 1)) + off = (off + 63) & ~63; + return off; +} + +/* size includes XSAVE_AREA_HEADER but not XSAVE_FORMAT (legacy save area). */ +static int xstate_get_compacted_size( UINT64 mask ) +{ + UINT64 compaction_mask; + unsigned int i; + int off; + + compaction_mask = ((UINT64)1 << 63) | mask; + mask >>= 2; + off = sizeof(XSAVE_AREA_HEADER); + i = 2; + while (mask) + { + if (mask == 1) return off + user_shared_data->XState.Features[i].Size; + off = next_compacted_xstate_offset( off, compaction_mask, i ); + mask >>= 1; + ++i; + } + return off; +} + +static int xstate_get_size( UINT64 mask ) +{ + unsigned int i; + + mask >>= 2; + if (!mask) return sizeof(XSAVE_AREA_HEADER); + i = 2; + while (mask != 1) + { + mask >>= 1; + ++i; + } + return user_shared_data->XState.Features[i].Offset + user_shared_data->XState.Features[i].Size - sizeof(XSAVE_FORMAT); +} /********************************************************************** * RtlGetExtendedContextLength2 (NTDLL.@) @@ -539,12 +585,12 @@ NTSTATUS WINAPI RtlGetExtendedContextLength2( ULONG context_flags, ULONG *length if (!(supported_mask = RtlGetEnabledExtendedFeatures( ~(ULONG64)0) )) return STATUS_NOT_SUPPORTED; - compaction_mask &= supported_mask; - - size = p->context_size + p->context_ex_size + offsetof(XSTATE, YmmContext) + 63; + size = p->context_size + p->context_ex_size + 63; - if (compaction_mask & supported_mask & (1 << XSTATE_AVX)) - size += sizeof(YMMCONTEXT); + compaction_mask &= supported_mask & ~(ULONG64)3; + if (user_shared_data->XState.CompactionEnabled) size += xstate_get_compacted_size( compaction_mask ); + else if (compaction_mask) size += xstate_get_size( compaction_mask ); + else size += sizeof(XSAVE_AREA_HEADER); *length = size; return STATUS_SUCCESS; @@ -595,11 +641,11 @@ NTSTATUS WINAPI RtlInitializeExtendedContext2( void *context, ULONG context_flag xs = (XSTATE *)(((ULONG_PTR)c_ex + p->context_ex_size + 63) & ~(ULONG_PTR)63); c_ex->XState.Offset = (ULONG_PTR)xs - (ULONG_PTR)c_ex; - c_ex->XState.Length = offsetof(XSTATE, YmmContext); compaction_mask &= supported_mask; - if (compaction_mask & (1 << XSTATE_AVX)) - c_ex->XState.Length += sizeof(YMMCONTEXT); + if (user_shared_data->XState.CompactionEnabled) c_ex->XState.Length = xstate_get_compacted_size( compaction_mask ); + else if (compaction_mask & ~(ULONG64)3) c_ex->XState.Length = xstate_get_size( compaction_mask ); + else c_ex->XState.Length = sizeof(XSAVE_AREA_HEADER); memset( xs, 0, c_ex->XState.Length ); if (user_shared_data->XState.CompactionEnabled) @@ -633,6 +679,10 @@ NTSTATUS WINAPI RtlInitializeExtendedContext( void *context, ULONG context_flags void * WINAPI RtlLocateExtendedFeature2( CONTEXT_EX *context_ex, ULONG feature_id, XSTATE_CONFIGURATION *xstate_config, ULONG *length ) { + UINT64 feature_mask = (ULONG64)1 << feature_id; + XSAVE_AREA_HEADER *xs; + unsigned int offset, i; + TRACE( "context_ex %p, feature_id %lu, xstate_config %p, length %p.\n", context_ex, feature_id, xstate_config, length ); @@ -648,16 +698,31 @@ void * WINAPI RtlLocateExtendedFeature2( CONTEXT_EX *context_ex, ULONG feature_i return NULL; } - if (feature_id != XSTATE_AVX) + if (feature_id < 2 || feature_id >= 64) return NULL; + xs = (XSAVE_AREA_HEADER *)((BYTE *)context_ex + context_ex->XState.Offset); + if (length) - *length = sizeof(YMMCONTEXT); + *length = xstate_config->Features[feature_id].Size; + + if (xstate_config->CompactionEnabled) + { + if (!(xs->CompactionMask & feature_mask)) return NULL; + offset = sizeof(XSAVE_AREA_HEADER); + for (i = 2; i < feature_id; ++i) + offset = next_compacted_xstate_offset( offset, xs->CompactionMask, i ); + } + else + { + if (!(feature_mask & xstate_config->EnabledFeatures)) return NULL; + offset = xstate_config->Features[feature_id].Offset - sizeof(XSAVE_FORMAT); + } - if (context_ex->XState.Length < sizeof(XSTATE)) + if (context_ex->XState.Length < offset + xstate_config->Features[feature_id].Size) return NULL; - return (BYTE *)context_ex + context_ex->XState.Offset + offsetof(XSTATE, YmmContext); + return (BYTE *)xs + offset; } @@ -787,8 +852,9 @@ NTSTATUS WINAPI RtlCopyContext( CONTEXT *dst, DWORD context_flags, CONTEXT *src NTSTATUS WINAPI RtlCopyExtendedContext( CONTEXT_EX *dst, ULONG context_flags, CONTEXT_EX *src ) { const struct context_parameters *p; - XSTATE *dst_xs, *src_xs; + XSAVE_AREA_HEADER *dst_xs, *src_xs; ULONG64 feature_mask; + unsigned int i, off, size; TRACE( "dst %p, context_flags %#lx, src %p.\n", dst, context_flags, src ); @@ -803,18 +869,35 @@ NTSTATUS WINAPI RtlCopyExtendedContext( CONTEXT_EX *dst, ULONG context_flags, CO if (!(context_flags & 0x40)) return STATUS_SUCCESS; - if (dst->XState.Length < offsetof(XSTATE, YmmContext)) + if (dst->XState.Length < sizeof(XSAVE_AREA_HEADER)) return STATUS_BUFFER_OVERFLOW; - dst_xs = (XSTATE *)((BYTE *)dst + dst->XState.Offset); - src_xs = (XSTATE *)((BYTE *)src + src->XState.Offset); + dst_xs = (XSAVE_AREA_HEADER *)((BYTE *)dst + dst->XState.Offset); + src_xs = (XSAVE_AREA_HEADER *)((BYTE *)src + src->XState.Offset); - memset(dst_xs, 0, offsetof(XSTATE, YmmContext)); + memset(dst_xs, 0, sizeof(XSAVE_AREA_HEADER)); dst_xs->Mask = (src_xs->Mask & ~(ULONG64)3) & feature_mask; dst_xs->CompactionMask = user_shared_data->XState.CompactionEnabled ? ((ULONG64)1 << 63) | (src_xs->CompactionMask & feature_mask) : 0; - if (dst_xs->Mask & 4 && src->XState.Length >= sizeof(XSTATE) && dst->XState.Length >= sizeof(XSTATE)) - memcpy( &dst_xs->YmmContext, &src_xs->YmmContext, sizeof(dst_xs->YmmContext) ); + + if (dst_xs->CompactionMask) feature_mask &= dst_xs->CompactionMask; + feature_mask = dst_xs->Mask >> 2; + + i = 2; + off = sizeof(XSAVE_AREA_HEADER); + while (1) + { + if (feature_mask & 1) + { + if (!dst_xs->CompactionMask) off = user_shared_data->XState.Features[i].Offset - sizeof(XSAVE_FORMAT); + size = user_shared_data->XState.Features[i].Size; + if (src->XState.Length < off + size || dst->XState.Length < off + size) break; + memcpy( (BYTE *)dst_xs + off, (BYTE *)src_xs + off, size ); + } + if (!(feature_mask >>= 1)) break; + if (dst_xs->CompactionMask) off = next_compacted_xstate_offset( off, dst_xs->CompactionMask, i); + ++i; + } return STATUS_SUCCESS; } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/5094
Hi, It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated. The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=143162 Your paranoid android. === debian11 (build log) === error: patch failed: dlls/ntdll/unix/signal_i386.c:607 error: patch failed: dlls/ntdll/unix/signal_x86_64.c:479 Task: Patch failed to apply === debian11b (build log) === error: patch failed: dlls/ntdll/unix/signal_i386.c:607 error: patch failed: dlls/ntdll/unix/signal_x86_64.c:479 Task: Patch failed to apply
participants (3)
-
Marvin -
Paul Gofman -
Paul Gofman (@gofman)