From 81a08cea79afccdf4daddda5936c05a30849f83a Mon Sep 17 00:00:00 2001 From: Paul Gofman Date: Tue, 1 Sep 2020 12:21:45 +0300 Subject: [PATCH] kernel32: Implement CopyContext(). Signed-off-by: Paul Gofman Signed-off-by: Alexandre Julliard --- .../api-ms-win-core-xstate-l1-1-0.spec | 2 +- .../api-ms-win-core-xstate-l2-1-0.spec | 2 +- dlls/kernel32/kernel32.spec | 2 +- dlls/kernelbase/kernelbase.spec | 2 +- dlls/kernelbase/memory.c | 56 +++ dlls/ntdll/exception.c | 85 +++- dlls/ntdll/ntdll.spec | 1 + dlls/ntdll/tests/exception.c | 365 ++++++++++++++++++ dlls/ntoskrnl.exe/ntoskrnl.exe.spec | 1 + include/ddk/wdm.h | 1 + include/winbase.h | 1 + 11 files changed, 512 insertions(+), 6 deletions(-) diff --git a/dlls/api-ms-win-core-xstate-l1-1-0/api-ms-win-core-xstate-l1-1-0.spec b/dlls/api-ms-win-core-xstate-l1-1-0/api-ms-win-core-xstate-l1-1-0.spec index 24f685bb0d9..8558ddbec0d 100644 --- a/dlls/api-ms-win-core-xstate-l1-1-0/api-ms-win-core-xstate-l1-1-0.spec +++ b/dlls/api-ms-win-core-xstate-l1-1-0/api-ms-win-core-xstate-l1-1-0.spec @@ -1,4 +1,4 @@ -@ stub RtlCopyExtendedContext +@ stdcall RtlCopyExtendedContext(ptr long ptr) ntdll.RtlCopyExtendedContext @ stdcall RtlGetEnabledExtendedFeatures(int64) ntdll.RtlGetEnabledExtendedFeatures @ stdcall RtlGetExtendedContextLength(long ptr) ntdll.RtlGetExtendedContextLength @ stdcall -ret64 RtlGetExtendedFeaturesMask(ptr) ntdll.RtlGetExtendedFeaturesMask diff --git a/dlls/api-ms-win-core-xstate-l2-1-0/api-ms-win-core-xstate-l2-1-0.spec b/dlls/api-ms-win-core-xstate-l2-1-0/api-ms-win-core-xstate-l2-1-0.spec index 9c804b28864..a0baac7d4c7 100644 --- a/dlls/api-ms-win-core-xstate-l2-1-0/api-ms-win-core-xstate-l2-1-0.spec +++ b/dlls/api-ms-win-core-xstate-l2-1-0/api-ms-win-core-xstate-l2-1-0.spec @@ -1,4 +1,4 @@ -@ stub CopyContext +@ stdcall -arch=i386,x86_64 CopyContext(ptr long ptr) kernel32.CopyContext @ stdcall -ret64 -arch=i386,x86_64 GetEnabledXStateFeatures() kernel32.GetEnabledXStateFeatures @ stdcall -arch=i386,x86_64 GetXStateFeaturesMask(ptr ptr) kernel32.GetXStateFeaturesMask @ stdcall -arch=i386,x86_64 InitializeContext(ptr long ptr ptr) kernel32.InitializeContext diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec index d357d32c23e..38eb1d5ece7 100644 --- a/dlls/kernel32/kernel32.spec +++ b/dlls/kernel32/kernel32.spec @@ -256,7 +256,7 @@ @ stdcall -import ConvertThreadToFiber(ptr) @ stdcall -import ConvertThreadToFiberEx(ptr long) @ stdcall ConvertToGlobalHandle(long) -# @ stub CopyContext +@ stdcall -import -arch=i386,x86_64 CopyContext(ptr long ptr) @ stdcall CopyFileA(str str long) @ stdcall CopyFileExA (str str ptr ptr ptr long) @ stdcall -import CopyFileExW(wstr wstr ptr ptr ptr long) diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec index e8e974d9c15..a794e33faf3 100644 --- a/dlls/kernelbase/kernelbase.spec +++ b/dlls/kernelbase/kernelbase.spec @@ -165,7 +165,7 @@ @ stdcall ConvertThreadToFiber(ptr) @ stdcall ConvertThreadToFiberEx(ptr long) @ stdcall ConvertToAutoInheritPrivateObjectSecurity(ptr ptr ptr ptr long ptr) -# @ stub CopyContext +@ stdcall -arch=i386,x86_64 CopyContext(ptr long ptr) # @ stub CopyFile2 @ stdcall CopyFileExW(wstr wstr ptr ptr ptr long) @ stdcall CopyFileW(wstr wstr long) diff --git a/dlls/kernelbase/memory.c b/dlls/kernelbase/memory.c index 38aa2c78410..4ead38f2bc0 100644 --- a/dlls/kernelbase/memory.c +++ b/dlls/kernelbase/memory.c @@ -1233,6 +1233,62 @@ BOOL WINAPI InitializeContext( void *buffer, DWORD context_flags, CONTEXT **cont { return InitializeContext2( buffer, context_flags, context, length, ~(ULONG64)0 ); } + +/*********************************************************************** + * CopyContext (kernelbase.@) + */ +BOOL WINAPI CopyContext( CONTEXT *dst, DWORD context_flags, CONTEXT *src ) +{ + DWORD context_size, arch_flag, flags_offset, dst_flags, src_flags; + static const DWORD arch_mask = 0x110000; + NTSTATUS status; + BYTE *d, *s; + + TRACE("dst %p, context_flags %#x, src %p.\n", dst, context_flags, src); + + if (context_flags & 0x40 && !RtlGetEnabledExtendedFeatures( ~(ULONG64)0 )) + { + SetLastError(ERROR_NOT_SUPPORTED); + return FALSE; + } + + arch_flag = context_flags & arch_mask; + + switch (arch_flag) + { + case 0x10000: context_size = 0x2cc; flags_offset = 0; break; + case 0x100000: context_size = 0x4d0; flags_offset = 0x30; break; + default: + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + + d = (BYTE *)dst; + s = (BYTE *)src; + dst_flags = *(DWORD *)(d + flags_offset); + src_flags = *(DWORD *)(s + flags_offset); + + if ((dst_flags & arch_mask) != arch_flag + || (src_flags & arch_mask) != arch_flag) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + + context_flags &= src_flags; + + if (context_flags & ~dst_flags & 0x40) + { + SetLastError(ERROR_MORE_DATA); + return FALSE; + } + + if ((status = RtlCopyExtendedContext( (CONTEXT_EX *)(d + context_size), context_flags, + (CONTEXT_EX *)(s + context_size) ))) + return set_ntstatus( status ); + + return TRUE; +} #endif diff --git a/dlls/ntdll/exception.c b/dlls/ntdll/exception.c index e022e2c2cd1..17bbb26f9e8 100644 --- a/dlls/ntdll/exception.c +++ b/dlls/ntdll/exception.c @@ -666,6 +666,24 @@ ULONG64 WINAPI RtlGetEnabledExtendedFeatures(ULONG64 feature_mask) return user_shared_data->XState.EnabledFeatures & feature_mask; } +struct context_copy_range +{ + ULONG start; + ULONG flag; +}; + +static const struct context_copy_range copy_ranges_amd64[] = +{ + {0x38, 0x1}, {0x3a, 0x4}, { 0x42, 0x1}, { 0x48, 0x10}, { 0x78, 0x2}, { 0x98, 0x1}, + {0xa0, 0x2}, {0xf8, 0x1}, {0x100, 0x8}, {0x2a0, 0}, {0x4b0, 0x10}, {0x4d0, 0} +}; + +static const struct context_copy_range copy_ranges_x86[] = +{ + { 0x4, 0x10}, {0x1c, 0x8}, {0x8c, 0x4}, {0x9c, 0x2}, {0xb4, 0x1}, {0xcc, 0x20}, {0x1ec, 0}, + {0x2cc, 0}, +}; + static const struct context_parameters { ULONG arch_flag; @@ -676,11 +694,12 @@ static const struct context_parameters ULONG alignment; /* Used when computing size of context. */ ULONG true_alignment; /* Used for actual alignment. */ ULONG flags_offset; + const struct context_copy_range *copy_ranges; } arch_context_paramaters[] = { - {0x00100000, 0xd810005f, 0x4d0, 0x4d0, 0x20, 7, 0xf, 0x30}, - {0x00010000, 0xd801007f, 0x2cc, 0xcc, 0x18, 3, 0x3, 0}, + {0x00100000, 0xd810005f, 0x4d0, 0x4d0, 0x20, 7, 0xf, 0x30, copy_ranges_amd64}, + {0x00010000, 0xd801007f, 0x2cc, 0xcc, 0x18, 3, 0x3, 0, copy_ranges_x86}, }; static const struct context_parameters *context_get_parameters( ULONG context_flags ) @@ -882,3 +901,65 @@ ULONG64 WINAPI RtlGetExtendedFeaturesMask( CONTEXT_EX *context_ex ) return xs->Mask & ~(ULONG64)3; } + + +/********************************************************************** + * RtlCopyExtendedContext (NTDLL.@) + */ +NTSTATUS WINAPI RtlCopyExtendedContext( CONTEXT_EX *dst, ULONG context_flags, CONTEXT_EX *src ) +{ + const struct context_copy_range *range; + const struct context_parameters *p; + XSTATE *dst_xs, *src_xs; + ULONG64 feature_mask; + unsigned int start; + BYTE *d, *s; + + TRACE( "dst %p, context_flags %#x, src %p.\n", dst, context_flags, src ); + + if (!(p = context_get_parameters( context_flags ))) + return STATUS_INVALID_PARAMETER; + + if (!(feature_mask = RtlGetEnabledExtendedFeatures( ~(ULONG64)0 )) && context_flags & 0x40) + return STATUS_NOT_SUPPORTED; + + d = RtlLocateLegacyContext( dst, NULL ); + s = RtlLocateLegacyContext( src, NULL ); + + *((ULONG *)(d + p->flags_offset)) |= context_flags; + + start = 0; + range = p->copy_ranges; + do + { + if (range->flag & context_flags) + { + if (!start) + start = range->start; + } + else if (start) + { + memcpy( d + start, s + start, range->start - start ); + start = 0; + } + } + while (range++->start != p->context_size); + + if (!(context_flags & 0x40)) + return STATUS_SUCCESS; + + if (dst->XState.Length < offsetof(XSTATE, YmmContext)) + return STATUS_BUFFER_OVERFLOW; + + dst_xs = (XSTATE *)((BYTE *)dst + dst->XState.Offset); + src_xs = (XSTATE *)((BYTE *)src + src->XState.Offset); + + memset(dst_xs, 0, offsetof(XSTATE, YmmContext)); + 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) ); + return STATUS_SUCCESS; +} diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index 2c58dc575c0..453c4827572 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -525,6 +525,7 @@ @ stub RtlConvertUiListToApiList @ stdcall -arch=win32 -ret64 RtlConvertUlongToLargeInteger(long) # @ stub RtlConvertVariantToProperty +@ stdcall RtlCopyExtendedContext(ptr long ptr) @ stdcall RtlCopyLuid(ptr ptr) @ stdcall RtlCopyLuidAndAttributesArray(long ptr ptr) @ stdcall -arch=x86_64 RtlCopyMemory(ptr ptr long) diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c index 660cc409548..b39153f0b50 100644 --- a/dlls/ntdll/tests/exception.c +++ b/dlls/ntdll/tests/exception.c @@ -51,6 +51,7 @@ static NTSTATUS (WINAPI *pRtlGetExtendedContextLength2)(ULONG context_flags, UL static NTSTATUS (WINAPI *pRtlInitializeExtendedContext)(void *context, ULONG context_flags, CONTEXT_EX **context_ex); static NTSTATUS (WINAPI *pRtlInitializeExtendedContext2)(void *context, ULONG context_flags, CONTEXT_EX **context_ex, ULONG64 compaction_mask); +static NTSTATUS (WINAPI *pRtlCopyExtendedContext)(CONTEXT_EX *dst, ULONG context_flags, CONTEXT_EX *src); static void * (WINAPI *pRtlLocateExtendedFeature)(CONTEXT_EX *context_ex, ULONG feature_id, ULONG *length); static void * (WINAPI *pRtlLocateLegacyContext)(CONTEXT_EX *context_ex, ULONG *length); static void (WINAPI *pRtlSetExtendedFeaturesMask)(CONTEXT_EX *context_ex, ULONG64 feature_mask); @@ -71,6 +72,7 @@ static BOOL (WINAPI *pInitializeContext2)(void *buffer, DWORD context_flags static void * (WINAPI *pLocateXStateFeature)(CONTEXT *context, DWORD feature_id, DWORD *length); static BOOL (WINAPI *pSetXStateFeaturesMask)(CONTEXT *context, DWORD64 feature_mask); static BOOL (WINAPI *pGetXStateFeaturesMask)(CONTEXT *context, DWORD64 *feature_mask); +static BOOL (WINAPI *pCopyContext)(CONTEXT *dst, DWORD context_flags, CONTEXT *src); #define RTL_UNLOAD_EVENT_TRACE_NUMBER 64 @@ -6811,6 +6813,365 @@ static void test_extended_context(void) for (i = 0; i < 8; ++i) ok(data[i] == test_extended_context_data[i], "Got unexpected data %#x, i %u.\n", data[i], i); } + +struct modified_range +{ + ULONG start; + ULONG flag; +}; + +#define check_changes_in_range(a, b, c, d) check_changes_in_range_(__FILE__, __LINE__, a, b, c, d) +static void check_changes_in_range_(const char *file, unsigned int line, const BYTE *p, + const struct modified_range *range, ULONG flags, unsigned int length) +{ + ULONG range_flag, flag; + unsigned int once = 0; + unsigned int i; + + range_flag = 0; + for (i = 0; i < length; i++) + { + if (i == range->start) + { + range_flag = range->flag; + ++range; + } + + if ((flag = range_flag) == ~0) + continue; + + if (flag & 0x80000000) + { + if (flag & flags && p[i] == 0xcc) + { + if (!once++) + ok(broken(1), "Matched broken result at %#x, flags %#x.\n", i, flags); + continue; + } + flag = 0; + } + + if (flag & flags && p[i] != 0xcc) + { + ok_(file, line)(0, "Got unexected byte %#x at %#x, flags %#x.\n", p[i], i, flags); + return; + } + else if (!(flag & flags) && p[i] != 0xdd) + { + ok_(file, line)(0, "Got unexected byte %#x at %#x, flags %#x.\n", p[i], i, flags); + return; + } + } + ok_(file, line)(1, "Range matches.\n"); +} + +static void test_copy_context(void) +{ + static const struct modified_range ranges_amd64[] = + { + {0x30, ~0}, {0x38, 0x1}, {0x3a, 0x4}, {0x42, 0x1}, {0x48, 0x10}, {0x78, 0x2}, {0x98, 0x1}, + {0xa0, 0x2}, {0xf8, 0x1}, {0x100, 0x8}, {0x2a0, 0x80000008}, {0x4b0, 0x10}, {0x4d0, ~0}, + {0x4e8, 0}, {0x500, ~0}, {0x640, 0}, {0x1000, 0}, + }; + static const struct modified_range ranges_x86[] = + { + {0x0, ~0}, {0x4, 0x10}, {0x1c, 0x8}, {0x8c, 0x4}, {0x9c, 0x2}, {0xb4, 0x1}, {0xcc, 0x20}, {0x1ec, 0x80000020}, + {0x2cc, ~0}, {0x294, 0}, {0x1000, 0}, + }; + static const struct modified_range single_range[] = + { + {0x0, 0x1}, {0x1000, 0}, + }; + + static const struct + { + ULONG flags; + } + tests[] = + { + /* AMD64 */ + {0x100000 | 0x01}, /* CONTEXT_CONTROL */ + {0x100000 | 0x02}, /* CONTEXT_INTEGER */ + {0x100000 | 0x04}, /* CONTEXT_SEGMENTS */ + {0x100000 | 0x08}, /* CONTEXT_FLOATING_POINT */ + {0x100000 | 0x10}, /* CONTEXT_DEBUG_REGISTERS */ + {0x100000 | 0x0b}, /* CONTEXT_FULL */ + {0x100000 | 0x40}, /* CONTEXT_XSTATE */ + {0x100000 | 0x1f}, /* CONTEXT_ALL */ + /* X86 */ + { 0x10000 | 0x01}, /* CONTEXT_CONTROL */ + { 0x10000 | 0x02}, /* CONTEXT_INTEGER */ + { 0x10000 | 0x04}, /* CONTEXT_SEGMENTS */ + { 0x10000 | 0x08}, /* CONTEXT_FLOATING_POINT */ + { 0x10000 | 0x10}, /* CONTEXT_DEBUG_REGISTERS */ + { 0x10000 | 0x20}, /* CONTEXT_EXTENDED_REGISTERS */ + { 0x10000 | 0x40}, /* CONTEXT_XSTATE */ + { 0x10000 | 0x3f}, /* CONTEXT_ALL */ + }; + static const ULONG arch_flags[] = {0x100000, 0x10000}; + + DECLSPEC_ALIGN(64) BYTE src_context_buffer[4096]; + DECLSPEC_ALIGN(64) BYTE dst_context_buffer[4096]; + ULONG64 enabled_features, expected_compaction; + unsigned int context_length, flags_offset, i; + CONTEXT_EX *src_ex, *dst_ex; + XSTATE *dst_xs, *src_xs; + BOOL compaction, bret; + CONTEXT *src, *dst; + NTSTATUS status; + DWORD length; + ULONG flags; + + if (!pRtlCopyExtendedContext) + { + win_skip("RtlCopyExtendedContext is not available.\n"); + return; + } + + if (!pRtlGetEnabledExtendedFeatures) + { + skip("RtlGetEnabledExtendedFeatures is not available.\n"); + return; + } + + enabled_features = pRtlGetEnabledExtendedFeatures(~(ULONG64)0); + + for (i = 0; i < ARRAY_SIZE(tests); ++i) + { + flags = tests[i].flags; + flags_offset = (flags & 0x100000) ? 0x30 : 0; + + memset(dst_context_buffer, 0xdd, sizeof(dst_context_buffer)); + memset(src_context_buffer, 0xcc, sizeof(src_context_buffer)); + + status = pRtlInitializeExtendedContext(src_context_buffer, flags, &src_ex); + if (enabled_features || !(flags & 0x40)) + { + ok(!status, "Got unexpected status %#x, flags %#x.\n", status, flags); + } + else + { + ok(status == STATUS_NOT_SUPPORTED, "Got unexpected status %#x, flags %#x.\n", status, flags); + continue; + } + status = pRtlInitializeExtendedContext(dst_context_buffer, flags, &dst_ex); + ok(!status, "Got unexpected status %#x, flags %#x.\n", status, flags); + + src = pRtlLocateLegacyContext(src_ex, NULL); + dst = pRtlLocateLegacyContext(dst_ex, NULL); + + *(DWORD *)((BYTE *)dst + flags_offset) = 0; + *(DWORD *)((BYTE *)src + flags_offset) = 0; + + src_xs = (XSTATE *)((BYTE *)src_ex + src_ex->XState.Offset); + memset(src_xs, 0xcc, sizeof(XSTATE)); + src_xs->Mask = 3; + src_xs->CompactionMask = ~(ULONG64)0; + + status = pRtlCopyExtendedContext(dst_ex, flags, src_ex); + ok(!status, "Got unexpected status %#x, flags %#x.\n", status, flags); + + context_length = (BYTE *)dst_ex - (BYTE *)dst + dst_ex->All.Length; + check_changes_in_range((BYTE *)dst, flags & 0x100000 ? &ranges_amd64[0] : &ranges_x86[0], + flags, context_length); + + ok(*(DWORD *)((BYTE *)dst + flags_offset) == flags, "Got unexpected ContextFlags %#x, flags %#x.\n", + *(DWORD *)((BYTE *)dst + flags_offset), flags); + + memset(dst_context_buffer, 0xdd, sizeof(dst_context_buffer)); + status = pRtlInitializeExtendedContext(dst_context_buffer, flags, &dst_ex); + ok(!status, "Got unexpected status %#x, flags %#x.\n", status, flags); + *(DWORD *)((BYTE *)src + flags_offset) = 0; + *(DWORD *)((BYTE *)dst + flags_offset) = 0; + SetLastError(0xdeadbeef); + bret = pCopyContext(dst, flags | 0x40, src); + ok((!bret && GetLastError() == (enabled_features ? ERROR_INVALID_PARAMETER : ERROR_NOT_SUPPORTED)) + || broken(!bret && GetLastError() == ERROR_INVALID_PARAMETER), + "Got unexpected bret %#x, GetLastError() %#x, flags %#x.\n", + bret, GetLastError(), flags); + ok(*(DWORD *)((BYTE *)dst + flags_offset) == 0, "Got unexpected ContextFlags %#x, flags %#x.\n", + *(DWORD *)((BYTE *)dst + flags_offset), flags); + check_changes_in_range((BYTE *)dst, flags & 0x100000 ? &ranges_amd64[0] : &ranges_x86[0], + 0, context_length); + + *(DWORD *)((BYTE *)dst + flags_offset) = flags & 0x110000; + *(DWORD *)((BYTE *)src + flags_offset) = flags; + SetLastError(0xdeadbeef); + bret = pCopyContext(dst, flags, src); + if (flags & 0x40) + ok((!bret && GetLastError() == ERROR_MORE_DATA) + || broken(!(flags & CONTEXT_NATIVE) && !bret && GetLastError() == ERROR_INVALID_PARAMETER), + "Got unexpected bret %#x, GetLastError() %#x, flags %#x.\n", + bret, GetLastError(), flags); + else + ok((bret && GetLastError() == 0xdeadbeef) + || broken(!(flags & CONTEXT_NATIVE) && !bret && GetLastError() == ERROR_INVALID_PARAMETER), + "Got unexpected bret %#x, GetLastError() %#x, flags %#x.\n", + bret, GetLastError(), flags); + if (bret) + { + ok(*(DWORD *)((BYTE *)dst + flags_offset) == flags, "Got unexpected ContextFlags %#x, flags %#x.\n", + *(DWORD *)((BYTE *)dst + flags_offset), flags); + check_changes_in_range((BYTE *)dst, flags & 0x100000 ? &ranges_amd64[0] : &ranges_x86[0], + flags, context_length); + } + else + { + ok(*(DWORD *)((BYTE *)dst + flags_offset) == (flags & 0x110000), + "Got unexpected ContextFlags %#x, flags %#x.\n", + *(DWORD *)((BYTE *)dst + flags_offset), flags); + check_changes_in_range((BYTE *)dst, flags & 0x100000 ? &ranges_amd64[0] : &ranges_x86[0], + 0, context_length); + } + } + + for (i = 0; i < ARRAY_SIZE(arch_flags); ++i) + { + flags = arch_flags[i] | 0x42; + flags_offset = (flags & 0x100000) ? 0x30 : 0; + context_length = (flags & 0x100000) ? 0x4d0 : 0x2cc; + + memset(dst_context_buffer, 0xdd, sizeof(dst_context_buffer)); + memset(src_context_buffer, 0xcc, sizeof(src_context_buffer)); + length = sizeof(src_context_buffer); + bret = pInitializeContext(src_context_buffer, flags, &src, &length); + ok(bret, "Got unexpected bret %#x, flags %#x.\n", bret, flags); + + length = sizeof(dst_context_buffer); + bret = pInitializeContext(dst_context_buffer, flags, &dst, &length); + ok(bret, "Got unexpected bret %#x, flags %#x.\n", bret, flags); + + dst_ex = (CONTEXT_EX *)((BYTE *)dst + context_length); + src_ex = (CONTEXT_EX *)((BYTE *)src + context_length); + + dst_xs = (XSTATE *)((BYTE *)dst_ex + dst_ex->XState.Offset); + src_xs = (XSTATE *)((BYTE *)src_ex + src_ex->XState.Offset); + + *(DWORD *)((BYTE *)dst + flags_offset) = 0; + *(DWORD *)((BYTE *)src + flags_offset) = 0; + + compaction = !!(src_xs->CompactionMask & ((ULONG64)1 << 63)); + expected_compaction = (compaction ? ((ULONG64)1 << (ULONG64)63) | enabled_features : 0); + + memset(&src_xs->YmmContext, 0xcc, sizeof(src_xs->YmmContext)); + src_xs->CompactionMask = ~(ULONG64)0; + + src_xs->Mask = 0; + memset(&dst_xs->YmmContext, 0xdd, sizeof(dst_xs->YmmContext)); + dst_xs->CompactionMask = 0xdddddddddddddddd; + dst_xs->Mask = 0xdddddddddddddddd; + dst_ex->XState.Length = 0; + status = pRtlCopyExtendedContext(dst_ex, flags, src_ex); + ok(status == (enabled_features ? STATUS_BUFFER_OVERFLOW : STATUS_NOT_SUPPORTED), + "Got unexpected status %#x, flags %#x.\n", status, flags); + + if (!enabled_features) + continue; + + ok(*(DWORD *)((BYTE *)dst + flags_offset) == flags, "Got unexpected ContextFlags %#x, flags %#x.\n", + *(DWORD *)((BYTE *)dst + flags_offset), flags); + + src_xs->Mask = ~(ULONG64)0; + + memset(&dst_xs->YmmContext, 0xdd, sizeof(dst_xs->YmmContext)); + dst_xs->CompactionMask = 0xdddddddddddddddd; + dst_xs->Mask = 0xdddddddddddddddd; + dst_ex->XState.Length = 0; + status = pRtlCopyExtendedContext(dst_ex, flags, src_ex); + ok(status == STATUS_BUFFER_OVERFLOW, "Got unexpected status %#x, flags %#x.\n", status, flags); + ok(*(DWORD *)((BYTE *)dst + flags_offset) == flags, "Got unexpected ContextFlags %#x, flags %#x.\n", + *(DWORD *)((BYTE *)dst + flags_offset), flags); + + ok(dst_xs->Mask == 0xdddddddddddddddd, "Got unexpected Mask %s.\n", + wine_dbgstr_longlong(dst_xs->Mask)); + ok(dst_xs->CompactionMask == 0xdddddddddddddddd, "Got unexpected CompactionMask %s.\n", + wine_dbgstr_longlong(dst_xs->CompactionMask)); + check_changes_in_range((BYTE *)&dst_xs->YmmContext, single_range, 0, sizeof(dst_xs->YmmContext)); + + src_xs->Mask = 3; + memset(&dst_xs->YmmContext, 0xdd, sizeof(dst_xs->YmmContext)); + dst_xs->CompactionMask = 0xdddddddddddddddd; + dst_xs->Mask = 0xdddddddddddddddd; + dst_ex->XState.Length = offsetof(XSTATE, YmmContext); + status = pRtlCopyExtendedContext(dst_ex, flags, src_ex); + ok(!status, "Got unexpected status %#x, flags %#x.\n", status, flags); + ok(*(DWORD *)((BYTE *)dst + flags_offset) == flags, "Got unexpected ContextFlags %#x, flags %#x.\n", + *(DWORD *)((BYTE *)dst + flags_offset), flags); + ok(dst_xs->Mask == 0, "Got unexpected Mask %s.\n", + wine_dbgstr_longlong(dst_xs->Mask)); + ok(dst_xs->CompactionMask == expected_compaction, + "Got unexpected CompactionMask %s.\n", wine_dbgstr_longlong(dst_xs->CompactionMask)); + check_changes_in_range((BYTE *)&dst_xs->YmmContext, single_range, 0, sizeof(dst_xs->YmmContext)); + + memset(&dst_xs->YmmContext, 0xdd, sizeof(dst_xs->YmmContext)); + dst_xs->CompactionMask = 0xdddddddddddddddd; + dst_xs->Mask = 0xdddddddddddddddd; + dst_ex->XState.Length = sizeof(XSTATE); + status = pRtlCopyExtendedContext(dst_ex, flags, src_ex); + ok(!status, "Got unexpected status %#x, flags %#x.\n", status, flags); + ok(dst_xs->Mask == 0, "Got unexpected Mask %s.\n", + wine_dbgstr_longlong(dst_xs->Mask)); + ok(dst_xs->CompactionMask == expected_compaction, + "Got unexpected CompactionMask %s.\n", wine_dbgstr_longlong(dst_xs->CompactionMask)); + check_changes_in_range((BYTE *)&dst_xs->YmmContext, single_range, 0, sizeof(dst_xs->YmmContext)); + + src_xs->Mask = 4; + memset(&dst_xs->YmmContext, 0xdd, sizeof(dst_xs->YmmContext)); + dst_xs->CompactionMask = 0xdddddddddddddddd; + dst_xs->Mask = 0xdddddddddddddddd; + status = pRtlCopyExtendedContext(dst_ex, flags, src_ex); + ok(!status, "Got unexpected status %#x, flags %#x.\n", status, flags); + ok(dst_xs->Mask == 4, "Got unexpected Mask %s.\n", + wine_dbgstr_longlong(dst_xs->Mask)); + ok(dst_xs->CompactionMask == expected_compaction, + "Got unexpected CompactionMask %s.\n", wine_dbgstr_longlong(dst_xs->CompactionMask)); + check_changes_in_range((BYTE *)&dst_xs->YmmContext, single_range, 1, sizeof(dst_xs->YmmContext)); + + src_xs->Mask = 3; + memset(&dst_xs->YmmContext, 0xdd, sizeof(dst_xs->YmmContext)); + dst_xs->CompactionMask = 0xdddddddddddddddd; + dst_xs->Mask = 0xdddddddddddddddd; + status = pRtlCopyExtendedContext(dst_ex, flags, src_ex); + ok(!status, "Got unexpected status %#x, flags %#x.\n", status, flags); + ok(dst_xs->Mask == 0, "Got unexpected Mask %s.\n", + wine_dbgstr_longlong(dst_xs->Mask)); + ok(dst_xs->CompactionMask == expected_compaction, + "Got unexpected CompactionMask %s.\n", wine_dbgstr_longlong(dst_xs->CompactionMask)); + check_changes_in_range((BYTE *)&dst_xs->YmmContext, single_range, 0, sizeof(dst_xs->YmmContext)); + + + *(DWORD *)((BYTE *)src + flags_offset) = arch_flags[i]; + + src_xs->Mask = 7; + memset(&dst_xs->YmmContext, 0xdd, sizeof(dst_xs->YmmContext)); + dst_xs->CompactionMask = 0xdddddddddddddddd; + dst_xs->Mask = 0xdddddddddddddddd; + status = pRtlCopyExtendedContext(dst_ex, flags, src_ex); + ok(!status, "Got unexpected status %#x, flags %#x.\n", status, flags); + ok(dst_xs->Mask == 4, "Got unexpected Mask %s.\n", + wine_dbgstr_longlong(dst_xs->Mask)); + ok(dst_xs->CompactionMask == expected_compaction, + "Got unexpected CompactionMask %s.\n", wine_dbgstr_longlong(dst_xs->CompactionMask)); + check_changes_in_range((BYTE *)&dst_xs->YmmContext, single_range, 1, sizeof(dst_xs->YmmContext)); + + src_xs->Mask = 7; + memset(&dst_xs->YmmContext, 0xdd, sizeof(dst_xs->YmmContext)); + dst_xs->CompactionMask = 0xdddddddddddddddd; + dst_xs->Mask = 0xdddddddddddddddd; + SetLastError(0xdeadbeef); + bret = pCopyContext(dst, flags, src); + ok((bret && GetLastError() == 0xdeadbeef) + || broken(!(flags & CONTEXT_NATIVE) && !bret && GetLastError() == ERROR_INVALID_PARAMETER), + "Got unexpected bret %#x, GetLastError() %#x, flags %#x.\n", + bret, GetLastError(), flags); + ok(dst_xs->Mask == 0xdddddddddddddddd || broken(dst_xs->Mask == 4), "Got unexpected Mask %s, flags %#x.\n", + wine_dbgstr_longlong(dst_xs->Mask), flags); + ok(dst_xs->CompactionMask == 0xdddddddddddddddd || broken(dst_xs->CompactionMask == expected_compaction), + "Got unexpected CompactionMask %s, flags %#x.\n", wine_dbgstr_longlong(dst_xs->CompactionMask), flags); + check_changes_in_range((BYTE *)&dst_xs->YmmContext, single_range, + dst_xs->Mask == 4, sizeof(dst_xs->YmmContext)); + } +} #endif START_TEST(exception) @@ -6865,6 +7226,7 @@ START_TEST(exception) X(RtlLocateLegacyContext); X(RtlSetExtendedFeaturesMask); X(RtlGetExtendedFeaturesMask); + X(RtlCopyExtendedContext); #undef X #define X(f) p##f = (void*)GetProcAddress(hkernel32, #f) @@ -6876,6 +7238,7 @@ START_TEST(exception) X(LocateXStateFeature); X(SetXStateFeaturesMask); X(GetXStateFeaturesMask); + X(CopyContext); #undef X if (pRtlAddVectoredExceptionHandler && pRtlRemoveVectoredExceptionHandler) @@ -6956,6 +7319,7 @@ START_TEST(exception) test_prot_fault(); test_kiuserexceptiondispatcher(); test_extended_context(); + test_copy_context(); #elif defined(__x86_64__) @@ -6995,6 +7359,7 @@ START_TEST(exception) else skip( "Dynamic unwind functions not found\n" ); test_extended_context(); + test_copy_context(); #elif defined(__aarch64__) diff --git a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec index ed09ffcd924..8892fde5054 100644 --- a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec +++ b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec @@ -1010,6 +1010,7 @@ @ stdcall -arch=win32 -ret64 RtlConvertLongToLargeInteger(long) @ stdcall RtlConvertSidToUnicodeString(ptr ptr long) @ stdcall -arch=win32 -ret64 RtlConvertUlongToLargeInteger(long) +@ stdcall RtlCopyExtendedContext(ptr long ptr) @ stdcall RtlCopyLuid(ptr ptr) @ stdcall RtlCopyLuidAndAttributesArray(long ptr ptr) @ stdcall -arch=x86_64 RtlCopyMemory(ptr ptr long) diff --git a/include/ddk/wdm.h b/include/ddk/wdm.h index 60f926d7c5a..6885de1cf89 100644 --- a/include/ddk/wdm.h +++ b/include/ddk/wdm.h @@ -1837,6 +1837,7 @@ BOOLEAN WINAPI PsGetVersion(ULONG*,ULONG*,ULONG*,UNICODE_STRING*); NTSTATUS WINAPI PsTerminateSystemThread(NTSTATUS); #if defined(__x86_64__) || defined(__i386__) +NTSTATUS WINAPI RtlCopyExtendedContext(CONTEXT_EX*,ULONG,CONTEXT_EX*); NTSTATUS WINAPI RtlInitializeExtendedContext(void*,ULONG,CONTEXT_EX**); NTSTATUS WINAPI RtlInitializeExtendedContext2(void*,ULONG,CONTEXT_EX**,ULONG64); ULONG64 WINAPI RtlGetEnabledExtendedFeatures(ULONG64); diff --git a/include/winbase.h b/include/winbase.h index 1c29db367c2..ab3155eb1e1 100644 --- a/include/winbase.h +++ b/include/winbase.h @@ -1827,6 +1827,7 @@ WINBASEAPI BOOL WINAPI CommConfigDialogW(LPCWSTR,HWND,LPCOMMCONFIG); WINBASEAPI BOOL WINAPI ConnectNamedPipe(HANDLE,LPOVERLAPPED); WINBASEAPI BOOL WINAPI ContinueDebugEvent(DWORD,DWORD,DWORD); WINBASEAPI HANDLE WINAPI ConvertToGlobalHandle(HANDLE hSrc); +WINBASEAPI BOOL WINAPI CopyContext(CONTEXT*, DWORD, CONTEXT*); WINBASEAPI BOOL WINAPI CopyFileA(LPCSTR,LPCSTR,BOOL); WINBASEAPI BOOL WINAPI CopyFileW(LPCWSTR,LPCWSTR,BOOL); #define CopyFile WINELIB_NAME_AW(CopyFile)