Module: wine Branch: master Commit: 6bc2c092327bae6cbf73b75fd33581ee5140a285 URL: https://gitlab.winehq.org/wine/wine/-/commit/6bc2c092327bae6cbf73b75fd33581e...
Author: Paul Gofman pgofman@codeweavers.com Date: Wed Jan 17 16:33:33 2024 -0600
ntdll: Support generic xstate in Unix-side manipulation functions.
---
dlls/ntdll/unix/signal_i386.c | 2 ++ dlls/ntdll/unix/signal_x86_64.c | 4 ++++ dlls/ntdll/unix/system.c | 48 +++++++++++++++++++++++++++++++++++++---- 3 files changed, 50 insertions(+), 4 deletions(-)
diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c index 94799522202..61f42806f5d 100644 --- a/dlls/ntdll/unix/signal_i386.c +++ b/dlls/ntdll/unix/signal_i386.c @@ -1139,6 +1139,8 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context ) if (context_ex->XState.Length < xstate_get_size( xstate->CompactionMask, xstate->Mask )) return STATUS_BUFFER_OVERFLOW; copy_xstate( xstate, &frame->xstate, xstate->Mask ); + /* copy_xstate may use avx in memcpy, restore xstate not to break the tests. */ + frame->restore_flags |= CONTEXT_XSTATE; } } /* update the cached version of the debug registers */ diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index f4a6fcce8ca..d8d16917942 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -1172,6 +1172,8 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context ) if (context_ex->XState.Length < xstate_get_size( xstate->CompactionMask, xstate->Mask )) return STATUS_BUFFER_OVERFLOW; copy_xstate( xstate, &frame->xstate, xstate->Mask ); + /* copy_xstate may use avx in memcpy, restore xstate not to break the tests. */ + frame->restore_flags |= CONTEXT_XSTATE; } } /* update the cached version of the debug registers */ @@ -1382,6 +1384,8 @@ NTSTATUS get_thread_wow64_context( HANDLE handle, void *ctx, ULONG size ) if (context_ex->XState.Length < xstate_get_size( xstate->CompactionMask, xstate->Mask )) return STATUS_BUFFER_OVERFLOW; copy_xstate( xstate, &frame->xstate, xstate->Mask ); + /* copy_xstate may use avx in memcpy, restore xstate not to break the tests. */ + frame->restore_flags |= CONTEXT_XSTATE; } } return STATUS_SUCCESS; diff --git a/dlls/ntdll/unix/system.c b/dlls/ntdll/unix/system.c index 4c6c4cd23e2..068eb9d6839 100644 --- a/dlls/ntdll/unix/system.c +++ b/dlls/ntdll/unix/system.c @@ -250,20 +250,60 @@ BOOL xstate_compaction_enabled = FALSE; UINT64 xstate_supported_features_mask; UINT64 xstate_features_size;
+static int xstate_feature_offset[64] = {0, 0, 576}; +static int xstate_feature_size[64] = {0, 0, 256}; +static UINT64 xstate_aligned_features; + +static int next_xstate_offset( int off, UINT64 compaction_mask, int feature_idx ) +{ + const UINT64 feature_mask = (UINT64)1 << feature_idx; + + if (!compaction_mask) return xstate_feature_offset[feature_idx + 1] - sizeof(XSAVE_FORMAT); + + if (compaction_mask & feature_mask) off += xstate_feature_size[feature_idx]; + if (xstate_aligned_features & (feature_mask << 1)) + off = (off + 63) & ~63; + return off; +} + unsigned int xstate_get_size( UINT64 compaction_mask, UINT64 mask ) { - if (!(mask & ((UINT64)1 << XSTATE_AVX))) return sizeof(XSAVE_AREA_HEADER); - return sizeof(XSAVE_AREA_HEADER) + sizeof(YMMCONTEXT); + unsigned int i; + int off; + + mask >>= 2; + off = sizeof(XSAVE_AREA_HEADER); + i = 2; + while (mask) + { + if (mask == 1) return off + xstate_feature_size[i]; + off = next_xstate_offset( off, compaction_mask, i ); + mask >>= 1; + ++i; + } + return off; }
void copy_xstate( XSAVE_AREA_HEADER *dst, XSAVE_AREA_HEADER *src, UINT64 mask ) { + unsigned int i; + int src_off, dst_off; + mask &= xstate_extended_features() & src->Mask; if (src->CompactionMask) mask &= src->CompactionMask; if (dst->CompactionMask) mask &= dst->CompactionMask; dst->Mask = (dst->Mask & ~xstate_extended_features()) | mask; - if (mask & ((UINT64)1 << XSTATE_AVX)) - *(YMMCONTEXT *)(dst + 1) = *(YMMCONTEXT *)(src + 1); + mask >>= 2; + src_off = dst_off = sizeof(XSAVE_AREA_HEADER); + i = 2; + while (1) + { + if (mask & 1) memcpy( (char *)dst + dst_off, (char *)src + src_off, xstate_feature_size[i] ); + if (!(mask >>= 1)) break; + src_off = next_xstate_offset( src_off, src->CompactionMask, i ); + dst_off = next_xstate_offset( dst_off, dst->CompactionMask, i ); + ++i; + } }
#define AUTH 0x68747541 /* "Auth" */