[PATCH 3/4] kernel32: Implement CopyContext().
Paul Gofman
pgofman at codeweavers.com
Tue Sep 1 04:21:45 CDT 2020
Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
---
.../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 4abed7d3252..bfb2f68aa40 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 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 c7083e0299c..9aa20034fa4 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 5d0857476ea..301b86e8d3c 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
@@ -6849,6 +6851,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)
@@ -6903,6 +7264,7 @@ START_TEST(exception)
X(RtlLocateLegacyContext);
X(RtlSetExtendedFeaturesMask);
X(RtlGetExtendedFeaturesMask);
+ X(RtlCopyExtendedContext);
#undef X
#define X(f) p##f = (void*)GetProcAddress(hkernel32, #f)
@@ -6914,6 +7276,7 @@ START_TEST(exception)
X(LocateXStateFeature);
X(SetXStateFeaturesMask);
X(GetXStateFeaturesMask);
+ X(CopyContext);
#undef X
if (pRtlAddVectoredExceptionHandler && pRtlRemoveVectoredExceptionHandler)
@@ -6994,6 +7357,7 @@ START_TEST(exception)
test_prot_fault();
test_kiuserexceptiondispatcher();
test_extended_context();
+ test_copy_context();
#elif defined(__x86_64__)
@@ -7033,6 +7397,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)
--
2.26.2
More information about the wine-devel
mailing list