[PATCH v4 2/4] kernel32: Implement InitializeContext[2]().
Paul Gofman
pgofman at codeweavers.com
Mon Aug 31 04:31:57 CDT 2020
Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
---
v2:
- fix legacy context length on x86.
v3:
- fix remaining legacy context length tests on x86;
- fix RtlInitializeExtendedContext return type (NTSTATUS vs ULONG).
- clear CONTEXT_XSTATE instead of failing in InitializeContext2() if no supported features.
- define for x86/x64 only.
v4:
- zero initialize extended state (newer Windows does that).
.../api-ms-win-core-xstate-l1-1-0.spec | 2 +-
.../api-ms-win-core-xstate-l2-1-0.spec | 2 +-
dlls/kernel32/kernel32.spec | 3 +-
dlls/kernelbase/kernelbase.spec | 3 +-
dlls/kernelbase/memory.c | 49 +++
dlls/ntdll/exception.c | 76 +++-
dlls/ntdll/ntdll.spec | 2 +
dlls/ntdll/tests/exception.c | 361 ++++++++++++++++--
dlls/ntoskrnl.exe/ntoskrnl.exe.spec | 2 +
include/ddk/wdm.h | 2 +
include/winbase.h | 2 +
11 files changed, 462 insertions(+), 42 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 15126e5ddfe..2c72d52e452 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
@@ -2,7 +2,7 @@
@ stdcall RtlGetEnabledExtendedFeatures(int64) ntdll.RtlGetEnabledExtendedFeatures
@ stdcall RtlGetExtendedContextLength(long ptr) ntdll.RtlGetExtendedContextLength
@ stub RtlGetExtendedFeaturesMask
-@ stub RtlInitializeExtendedContext
+@ stdcall RtlInitializeExtendedContext(ptr long ptr) ntdll.RtlInitializeExtendedContext
@ stub RtlLocateExtendedFeature
@ stub RtlLocateLegacyContext
@ stub RtlSetExtendedFeaturesMask
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 f0510978198..3329be6cf08 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,6 +1,6 @@
@ stub CopyContext
@ stdcall -ret64 -arch=i386,x86_64 GetEnabledXStateFeatures() kernel32.GetEnabledXStateFeatures
@ stub GetXStateFeaturesMask
-@ stub InitializeContext
+@ stdcall -arch=i386,x86_64 InitializeContext(ptr long ptr ptr) kernel32.InitializeContext
@ stub LocateXStateFeature
@ stub SetXStateFeaturesMask
diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec
index 5671ae7e93d..c2649809b33 100644
--- a/dlls/kernel32/kernel32.spec
+++ b/dlls/kernel32/kernel32.spec
@@ -950,7 +950,8 @@
@ stdcall InitOnceExecuteOnce(ptr ptr ptr ptr) kernelbase.InitOnceExecuteOnce
@ stdcall InitOnceInitialize(ptr) ntdll.RtlRunOnceInitialize
@ stdcall InitializeConditionVariable(ptr) ntdll.RtlInitializeConditionVariable
-# @ stub InitializeContext
+@ stdcall -import -arch=i386,x86_64 InitializeContext(ptr long ptr ptr)
+@ stdcall -import -arch=i386,x86_64 InitializeContext2(ptr long ptr ptr int64)
@ stdcall InitializeCriticalSection(ptr) ntdll.RtlInitializeCriticalSection
@ stdcall -import InitializeCriticalSectionAndSpinCount(ptr long)
@ stdcall -import InitializeCriticalSectionEx(ptr long long)
diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec
index e8989a0639d..31be4761391 100644
--- a/dlls/kernelbase/kernelbase.spec
+++ b/dlls/kernelbase/kernelbase.spec
@@ -801,7 +801,8 @@
@ stdcall InitOnceInitialize(ptr) ntdll.RtlRunOnceInitialize
@ stdcall InitializeAcl(ptr long long)
@ stdcall InitializeConditionVariable(ptr) ntdll.RtlInitializeConditionVariable
-# @ stub InitializeContext
+@ stdcall -arch=i386,x86_64 InitializeContext(ptr long ptr ptr)
+@ stdcall -arch=i386,x86_64 InitializeContext2(ptr long ptr ptr int64)
@ stdcall InitializeCriticalSection(ptr) ntdll.RtlInitializeCriticalSection
@ stdcall InitializeCriticalSectionAndSpinCount(ptr long)
@ stdcall InitializeCriticalSectionEx(ptr long long)
diff --git a/dlls/kernelbase/memory.c b/dlls/kernelbase/memory.c
index 9131b9de28f..6576e900d5f 100644
--- a/dlls/kernelbase/memory.c
+++ b/dlls/kernelbase/memory.c
@@ -1184,6 +1184,55 @@ DWORD64 WINAPI GetEnabledXStateFeatures(void)
TRACE( "\n" );
return RtlGetEnabledExtendedFeatures( ~(ULONG64)0 );
}
+
+
+/***********************************************************************
+ * InitializeContext2 (kernelbase.@)
+ */
+BOOL WINAPI InitializeContext2( void *buffer, DWORD context_flags, CONTEXT **context, DWORD *length,
+ ULONG64 compaction_mask )
+{
+ ULONG orig_length;
+ NTSTATUS status;
+
+ TRACE( "buffer %p, context_flags %#x, context %p, ret_length %p, compaction_mask %s.\n",
+ buffer, context_flags, context, length, wine_dbgstr_longlong(compaction_mask) );
+
+ orig_length = *length;
+
+ if ((status = RtlGetExtendedContextLength2( context_flags, length, compaction_mask )))
+ {
+ if (status == STATUS_NOT_SUPPORTED && context_flags & 0x40)
+ {
+ context_flags &= ~0x40;
+ status = RtlGetExtendedContextLength2( context_flags, length, compaction_mask );
+ }
+
+ if (status)
+ return set_ntstatus( status );
+ }
+
+ if (!buffer || orig_length < *length)
+ {
+ SetLastError( ERROR_INSUFFICIENT_BUFFER );
+ return FALSE;
+ }
+
+ if ((status = RtlInitializeExtendedContext2( buffer, context_flags, (CONTEXT_EX **)context, compaction_mask )))
+ return set_ntstatus( status );
+
+ *context = (CONTEXT *)((BYTE *)*context + (*(CONTEXT_EX **)context)->Legacy.Offset);
+
+ return TRUE;
+}
+
+/***********************************************************************
+ * InitializeContext (kernelbase.@)
+ */
+BOOL WINAPI InitializeContext( void *buffer, DWORD context_flags, CONTEXT **context, DWORD *length )
+{
+ return InitializeContext2( buffer, context_flags, context, length, ~(ULONG64)0 );
+}
#endif
diff --git a/dlls/ntdll/exception.c b/dlls/ntdll/exception.c
index 9f65bb0464a..7aa059775c7 100644
--- a/dlls/ntdll/exception.c
+++ b/dlls/ntdll/exception.c
@@ -671,13 +671,16 @@ static const struct context_parameters
ULONG arch_flag;
ULONG supported_flags;
ULONG context_size; /* sizeof(CONTEXT) */
+ ULONG legacy_size; /* Legacy context size */
ULONG context_ex_size; /* sizeof(CONTEXT_EX) */
- ULONG alignment;
+ ULONG alignment; /* Used when computing size of context. */
+ ULONG true_alignment; /* Used for actual alignment. */
+ ULONG flags_offset;
}
arch_context_paramaters[] =
{
- {0x00100000, 0xd810005f, 0x4d0, 0x20, 7},
- {0x00010000, 0xd801007f, 0x2cc, 0x18, 3},
+ {0x00100000, 0xd810005f, 0x4d0, 0x4d0, 0x20, 7, 0xf, 0x30},
+ {0x00010000, 0xd801007f, 0x2cc, 0xcc, 0x18, 3, 0x3, 0},
};
static const struct context_parameters *context_get_parameters( ULONG context_flags )
@@ -736,3 +739,70 @@ NTSTATUS WINAPI RtlGetExtendedContextLength( ULONG context_flags, ULONG *length
{
return RtlGetExtendedContextLength2( context_flags, length, ~(ULONG64)0 );
}
+
+
+/**********************************************************************
+ * RtlInitializeExtendedContext2 (NTDLL.@)
+ */
+NTSTATUS WINAPI RtlInitializeExtendedContext2( void *context, ULONG context_flags, CONTEXT_EX **context_ex,
+ ULONG64 compaction_mask )
+{
+ const struct context_parameters *p;
+ ULONG64 supported_mask = 0;
+ CONTEXT_EX *c_ex;
+
+ TRACE( "context %p, context_flags %#x, context_ex %p, compaction_mask %s.\n",
+ context, context_flags, context_ex, wine_dbgstr_longlong(compaction_mask));
+
+ if (!(p = context_get_parameters( context_flags )))
+ return STATUS_INVALID_PARAMETER;
+
+ if ((context_flags & 0x40) && !(supported_mask = RtlGetEnabledExtendedFeatures( ~(ULONG64)0 )))
+ return STATUS_NOT_SUPPORTED;
+
+ context = (void *)(((ULONG_PTR)context + p->true_alignment) & ~p->true_alignment);
+ *(ULONG *)((BYTE *)context + p->flags_offset) = context_flags;
+
+ *context_ex = c_ex = (CONTEXT_EX *)((BYTE *)context + p->context_size);
+ c_ex->Legacy.Offset = c_ex->All.Offset = -(LONG)p->context_size;
+ c_ex->Legacy.Length = context_flags & 0x20 ? p->context_size : p->legacy_size;
+
+ if (context_flags & 0x40)
+ {
+ XSTATE *xs;
+
+ compaction_mask &= supported_mask;
+
+ 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);
+
+ memset( xs, 0, c_ex->XState.Length );
+ if (user_shared_data->XState.CompactionEnabled)
+ xs->CompactionMask = ((ULONG64)1 << 63) | compaction_mask;
+
+ c_ex->All.Length = p->context_size + c_ex->XState.Offset + c_ex->XState.Length;
+ }
+ else
+ {
+ c_ex->XState.Offset = 25; /* According to the tests, it is just 25 if CONTEXT_XSTATE is not specified. */
+ c_ex->XState.Length = 0;
+ c_ex->All.Length = p->context_size + 24; /* sizeof(CONTEXT_EX) minus 8 alignment bytes on x64. */
+ }
+
+ return STATUS_SUCCESS;
+}
+
+
+/**********************************************************************
+ * RtlInitializeExtendedContext (NTDLL.@)
+ */
+NTSTATUS WINAPI RtlInitializeExtendedContext( void *context, ULONG context_flags, CONTEXT_EX **context_ex )
+{
+ return RtlInitializeExtendedContext2( context, context_flags, context_ex, ~(ULONG64)0 );
+}
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec
index 24e8f4a8f9d..3f216d6efc3 100644
--- a/dlls/ntdll/ntdll.spec
+++ b/dlls/ntdll/ntdll.spec
@@ -757,6 +757,8 @@
@ stdcall RtlInitializeCriticalSection(ptr)
@ stdcall RtlInitializeCriticalSectionAndSpinCount(ptr long)
@ stdcall RtlInitializeCriticalSectionEx(ptr long long)
+@ stdcall RtlInitializeExtendedContext(ptr long ptr)
+@ stdcall RtlInitializeExtendedContext2(ptr long ptr int64)
@ stdcall RtlInitializeGenericTable(ptr ptr ptr ptr ptr)
@ stdcall RtlInitializeGenericTableAvl(ptr ptr ptr ptr ptr)
@ stdcall RtlInitializeHandleTable(long long ptr)
diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c
index a67e50af6ab..7f208a976e4 100644
--- a/dlls/ntdll/tests/exception.c
+++ b/dlls/ntdll/tests/exception.c
@@ -47,6 +47,9 @@ static void (WINAPI *pRtlSetUnhandledExceptionFilter)(PRTL_EXCEPTION_FILTER
static ULONG64 (WINAPI *pRtlGetEnabledExtendedFeatures)(ULONG64);
static NTSTATUS (WINAPI *pRtlGetExtendedContextLength)(ULONG context_flags, ULONG *length);
static NTSTATUS (WINAPI *pRtlGetExtendedContextLength2)(ULONG context_flags, ULONG *length, ULONG64 compaction_mask);
+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 *pNtReadVirtualMemory)(HANDLE, const void*, void*, SIZE_T, SIZE_T*);
static NTSTATUS (WINAPI *pNtTerminateProcess)(HANDLE handle, LONG exit_code);
static NTSTATUS (WINAPI *pNtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG);
@@ -56,6 +59,10 @@ static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL);
static NTSTATUS (WINAPI *pNtClose)(HANDLE);
static NTSTATUS (WINAPI *pNtSuspendProcess)(HANDLE process);
static NTSTATUS (WINAPI *pNtResumeProcess)(HANDLE process);
+static BOOL (WINAPI *pInitializeContext)(void *buffer, DWORD context_flags, CONTEXT **context,
+ DWORD *length);
+static BOOL (WINAPI *pInitializeContext2)(void *buffer, DWORD context_flags, CONTEXT **context,
+ DWORD *length, ULONG64 compaction_mask);
#define RTL_UNLOAD_EVENT_TRACE_NUMBER 64
@@ -6018,6 +6025,7 @@ static const unsigned test_extended_context_spoil_data1[8] = {0x10, 0x20, 0x30,
static const unsigned test_extended_context_spoil_data2[8] = {0x15, 0x25, 0x35, 0x45, 0x55, 0x65, 0x75, 0x85};
static BOOL test_extended_context_modified_state;
+static BOOL compaction_enabled;
static DWORD test_extended_context_handler(EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame,
CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher)
@@ -6026,14 +6034,8 @@ static DWORD test_extended_context_handler(EXCEPTION_RECORD *rec, EXCEPTION_REGI
CONTEXT_EX *xctx = (CONTEXT_EX *)(context + 1);
unsigned int *context_ymm_data;
DWORD expected_min_offset;
- BOOL compaction;
- int regs[4];
XSTATE *xs;
- /* Since we got xstates enabled by OS this cpuid level should be supported. */
- __cpuidex(regs, 0xd, 1);
- compaction = regs[0] & 2;
-
ok((context->ContextFlags & (CONTEXT_FULL | CONTEXT_XSTATE)) == (CONTEXT_FULL | CONTEXT_XSTATE),
"Got unexpected ContextFlags %#x.\n", context->ContextFlags);
@@ -6064,9 +6066,9 @@ static DWORD test_extended_context_handler(EXCEPTION_RECORD *rec, EXCEPTION_REGI
context_ymm_data = (unsigned int *)&xs->YmmContext;
ok(!((ULONG_PTR)xs % 64), "Got unexpected xs %p.\n", xs);
- ok((compaction && (xs->CompactionMask & (expected_compaction_mask | 3)) == expected_compaction_mask)
- || (!compaction && !xs->CompactionMask), "Got unexpected CompactionMask %s, compaction %#x.\n",
- wine_dbgstr_longlong(xs->CompactionMask), compaction);
+ ok((compaction_enabled && (xs->CompactionMask & (expected_compaction_mask | 3)) == expected_compaction_mask)
+ || (!compaction_enabled && !xs->CompactionMask), "Got unexpected CompactionMask %s, compaction %#x.\n",
+ wine_dbgstr_longlong(xs->CompactionMask), compaction_enabled);
if (test_extended_context_modified_state)
{
@@ -6139,8 +6141,10 @@ static void test_extended_context(void)
ULONG supported_flags;
ULONG broken_flags;
ULONG context_length;
+ ULONG legacy_length;
ULONG context_ex_length;
ULONG align;
+ ULONG flags_offset;
}
context_arch[] =
{
@@ -6149,24 +6153,34 @@ static void test_extended_context(void)
0xd800005f,
0xd8000000,
0x4d0, /* sizeof(CONTEXT) */
+ 0x4d0, /* sizeof(CONTEXT) */
0x20, /* sizeof(CONTEXT_EX) */
7,
+ 0x30,
},
{
0x00010000, /* CONTEXT_X86 */
0xd800007f,
0xd8000000,
0x2cc, /* sizeof(CONTEXT) */
+ 0xcc, /* offsetof(CONTEXT, ExtendedRegisters) */
0x18, /* sizeof(CONTEXT_EX) */
3,
+ 0,
},
};
- ULONG expected_length, expected_length_xstate;
- unsigned int i, address_offset, test;
+ ULONG expected_length, expected_length_xstate, context_flags, expected_offset;
+ DECLSPEC_ALIGN(64) BYTE context_buffer2[2048];
+ DECLSPEC_ALIGN(64) BYTE context_buffer[2048];
+ unsigned int i, j, address_offset, test;
+ ULONG ret, ret2, length, length2, align;
ULONG64 enabled_features;
- ULONG ret, length;
+ CONTEXT_EX *context_ex;
+ CONTEXT *context;
unsigned data[8];
ULONG flags;
+ XSTATE *xs;
+ BOOL bret;
address_offset = sizeof(void *) == 8 ? 2 : 1;
*(void **)(except_code_set_ymm0 + address_offset) = data;
@@ -6180,6 +6194,14 @@ static void test_extended_context(void)
enabled_features = pRtlGetEnabledExtendedFeatures(~(ULONG64)0);
+ if (enabled_features)
+ {
+ int regs[4];
+
+ __cpuidex(regs, 0xd, 1);
+ compaction_enabled = regs[0] & 2;
+ }
+
/* Test context manipulation functions. */
length = 0xdeadbeef;
ret = pRtlGetExtendedContextLength(0, &length);
@@ -6205,7 +6227,7 @@ static void test_extended_context(void)
continue;
flags = context_arch[test].flag | (1 << i);
- length = 0xdeadbeef;
+ length = length2 = 0xdeadbeef;
ret = pRtlGetExtendedContextLength(flags, &length);
if ((context_arch[test].supported_flags & flags) || flags == context_arch[test].flag)
@@ -6221,6 +6243,133 @@ static void test_extended_context(void)
ok(ret == STATUS_INVALID_PARAMETER && length == 0xdeadbeef,
"Got unexpected result ret %#x, length %#x, flags 0x%08x.\n", ret, length, flags);
}
+
+ SetLastError(0xdeadbeef);
+ bret = pInitializeContext(NULL, flags, NULL, &length2);
+ ok(!bret && length2 == length && GetLastError()
+ == (!ret ? ERROR_INSUFFICIENT_BUFFER : ERROR_INVALID_PARAMETER),
+ "Got unexpected bret %#x, length2 %#x, GetLastError() %u, flags %#x.\n",
+ bret, length2, GetLastError(), flags);
+
+ if (GetLastError() == ERROR_INVALID_PARAMETER)
+ continue;
+
+ SetLastError(0xdeadbeef);
+ context = (void *)0xdeadbeef;
+ length2 = expected_length - 1;
+ bret = pInitializeContext(context_buffer, flags, &context, &length2);
+ ok(!bret && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
+ "Got unexpected bret %#x, GetLastError() %u, flags %#x.\n", bret, GetLastError(), flags);
+ ok(context == (void *)0xdeadbeef, "Got unexpected context %p.\n", context);
+
+ SetLastError(0xdeadbeef);
+ memset(context_buffer, 0xcc, sizeof(context_buffer));
+ length2 = expected_length;
+ bret = pInitializeContext(context_buffer, flags, &context, &length2);
+ ok(bret && GetLastError() == 0xdeadbeef,
+ "Got unexpected bret %#x, GetLastError() %u, flags %#x.\n", bret, GetLastError(), flags);
+ ok(length2 == expected_length, "Got unexpexted length %#x.\n", length);
+ ok((BYTE *)context == context_buffer, "Got unexpected context %p, flags %#x.\n", context, flags);
+
+ context_flags = *(DWORD *)(context_buffer + context_arch[test].flags_offset);
+ ok(context_flags == flags, "Got unexpected ContextFlags %#x, flags %#x.\n", context_flags, flags);
+
+ context_ex = (CONTEXT_EX *)(context_buffer + context_arch[test].context_length);
+ ok(context_ex->Legacy.Offset == -(int)context_arch[test].context_length,
+ "Got unexpected Offset %d, flags %#x.\n", context_ex->Legacy.Offset, flags);
+ ok(context_ex->Legacy.Length == ((flags & 0x20) ? context_arch[test].context_length
+ : context_arch[test].legacy_length),
+ "Got unexpected Length %#x, flags %#x.\n", context_ex->Legacy.Length, flags);
+ ok(context_ex->All.Offset == -(int)context_arch[test].context_length,
+ "Got unexpected Offset %d, flags %#x.\n", context_ex->All.Offset, flags);
+
+ /* No extra 8 bytes in x64 CONTEXT_EX here. */
+ ok(context_ex->All.Length == context_arch[test].context_length + context_arch[1].context_ex_length,
+ "Got unexpected Length %#x, flags %#x.\n", context_ex->All.Length, flags);
+
+ ok(context_ex->XState.Offset == 25,
+ "Got unexpected Offset %d, flags %#x.\n", context_ex->XState.Offset, flags);
+ ok(!context_ex->XState.Length,
+ "Got unexpected Length %#x, flags %#x.\n", context_ex->XState.Length, flags);
+
+
+ for (j = 0; j < context_arch[test].flags_offset; ++j)
+ {
+ if (context_buffer[j] != 0xcc)
+ {
+ ok(0, "Buffer data changed at offset %#x.\n", j);
+ break;
+ }
+ }
+ for (j = context_arch[test].flags_offset + sizeof(context_flags);
+ j < context_arch[test].context_length; ++j)
+ {
+ if (context_buffer[j] != 0xcc)
+ {
+ ok(0, "Buffer data changed at offset %#x.\n", j);
+ break;
+ }
+ }
+ for (j = context_arch[test].context_length + context_arch[test].context_ex_length;
+ j < sizeof(context_buffer); ++j)
+ {
+ if (context_buffer[j] != 0xcc)
+ {
+ ok(0, "Buffer data changed at offset %#x.\n", j);
+ break;
+ }
+ }
+
+ memset(context_buffer2, 0xcc, sizeof(context_buffer2));
+ ret2 = pRtlInitializeExtendedContext(context_buffer2, flags, &context_ex);
+ ok(!ret2, "Got unexpected ret2 %#x, flags %#x.\n", ret2, flags);
+ ok(!memcmp(context_buffer2, context_buffer, sizeof(context_buffer2)),
+ "Context data do not match, flags %#x.\n", flags);
+
+ memset(context_buffer2, 0xcc, sizeof(context_buffer2));
+ ret2 = pRtlInitializeExtendedContext(context_buffer2 + 2, flags, &context_ex);
+ ok(!ret2, "Got unexpected ret2 %#x, flags %#x.\n", ret2, flags);
+
+ /* Buffer gets aligned to 16 bytes on x64, while returned context length suggests it should be 8. */
+ align = test ? 4 : 16;
+ ok(!memcmp(context_buffer2 + align, context_buffer,
+ sizeof(context_buffer2) - align),
+ "Context data do not match, flags %#x.\n", flags);
+
+ SetLastError(0xdeadbeef);
+ memset(context_buffer2, 0xcc, sizeof(context_buffer2));
+ bret = pInitializeContext(context_buffer2 + 2, flags, &context, &length2);
+ ok(bret && GetLastError() == 0xdeadbeef,
+ "Got unexpected bret %#x, GetLastError() %u, flags %#x.\n", bret, GetLastError(), flags);
+ ok(length2 == expected_length, "Got unexpexted length %#x.\n", length);
+ ok(!memcmp(context_buffer2 + align, context_buffer,
+ sizeof(context_buffer2) - align),
+ "Context data do not match, flags %#x.\n", flags);
+
+ if (!pRtlInitializeExtendedContext2 || !pInitializeContext2)
+ {
+ static int once;
+
+ if (!once++)
+ win_skip("InitializeContext2 is not available.\n");
+ continue;
+ }
+
+ memset(context_buffer2, 0xcc, sizeof(context_buffer2));
+ ret2 = pRtlInitializeExtendedContext2(context_buffer2 + 2, flags, &context_ex, ~(ULONG64)0);
+ ok(!ret2, "Got unexpected ret2 %#x, flags %#x.\n", ret2, flags);
+ ok(!memcmp(context_buffer2 + align, context_buffer,
+ sizeof(context_buffer2) - align),
+ "Context data do not match, flags %#x.\n", flags);
+
+ memset(context_buffer2, 0xcc, sizeof(context_buffer2));
+ bret = pInitializeContext2(context_buffer2 + 2, flags, &context, &length2, ~(ULONG64)0);
+ ok(bret && GetLastError() == 0xdeadbeef,
+ "Got unexpected bret %#x, GetLastError() %u, flags %#x.\n", bret, GetLastError(), flags);
+ ok(length2 == expected_length, "Got unexpexted length %#x.\n", length);
+ ok(!memcmp(context_buffer2 + align, context_buffer,
+ sizeof(context_buffer2) - align),
+ "Context data do not match, flags %#x.\n", flags);
}
flags = context_arch[test].flag | 0x40;
@@ -6232,6 +6381,31 @@ static void test_extended_context(void)
{
ok(ret == STATUS_NOT_SUPPORTED && length == 0xdeadbeef,
"Got unexpected result ret %#x, length %#x.\n", ret, length);
+
+ context_ex = (void *)0xdeadbeef;
+ ret2 = pRtlInitializeExtendedContext(context_buffer, flags, &context_ex);
+ ok(ret2 == STATUS_NOT_SUPPORTED, "Got unexpected result ret %#x, test %u.\n", ret2, test);
+
+ SetLastError(0xdeadbeef);
+ length2 = sizeof(context_buffer);
+ bret = pInitializeContext(context_buffer, flags, &context, &length2);
+ ok(bret && GetLastError() == 0xdeadbeef,
+ "Got unexpected bret %#x, GetLastError() %u, flags %#x.\n", bret, GetLastError(), flags);
+ context_flags = *(DWORD *)(context_buffer + context_arch[test].flags_offset);
+ ok(context_flags == (flags & ~0x40), "Got unexpected ContextFlags %#x, flags %#x.\n",
+ context_flags, flags);
+
+ if (pInitializeContext2)
+ {
+ SetLastError(0xdeadbeef);
+ length2 = sizeof(context_buffer);
+ bret = pInitializeContext2(context_buffer, flags, &context, &length2, ~(ULONG64)0);
+ ok(bret && GetLastError() == 0xdeadbeef,
+ "Got unexpected bret %#x, GetLastError() %u, flags %#x.\n", bret, GetLastError(), flags);
+ context_flags = *(DWORD *)(context_buffer + context_arch[test].flags_offset);
+ ok(context_flags == (flags & ~0x40), "Got unexpected ContextFlags %#x, flags %#x.\n",
+ context_flags, flags);
+ }
continue;
}
@@ -6241,39 +6415,148 @@ static void test_extended_context(void)
if (!pRtlGetExtendedContextLength2)
{
win_skip("RtlGetExtendedContextLength2 is not available.\n");
- continue;
}
+ else
+ {
+ length = 0xdeadbeef;
+ ret = pRtlGetExtendedContextLength2(flags, &length, 7);
+ ok(!ret && length == expected_length_xstate,
+ "Got unexpected result ret %#x, length %#x, test %u.\n", ret, length, test);
- length = 0xdeadbeef;
- ret = pRtlGetExtendedContextLength2(flags, &length, 7);
- ok(!ret && length == expected_length_xstate,
- "Got unexpected result ret %#x, length %#x, test %u.\n", ret, length, test);
+ length = 0xdeadbeef;
+ ret = pRtlGetExtendedContextLength2(flags, &length, ~0);
+ ok(!ret && length >= expected_length_xstate,
+ "Got unexpected result ret %#x, length %#x, test %u.\n", ret, length, test);
- length = 0xdeadbeef;
- ret = pRtlGetExtendedContextLength2(flags, &length, ~0);
- ok(!ret && length >= expected_length_xstate,
- "Got unexpected result ret %#x, length %#x, test %u.\n", ret, length, test);
+ length = 0xdeadbeef;
+ ret = pRtlGetExtendedContextLength2(flags, &length, 0);
+ ok(!ret && length == expected_length_xstate - sizeof(YMMCONTEXT),
+ "Got unexpected result ret %#x, length %#x, test %u.\n", ret, length, test);
- length = 0xdeadbeef;
- ret = pRtlGetExtendedContextLength2(flags, &length, 0);
- ok(!ret && length == expected_length_xstate - sizeof(YMMCONTEXT),
- "Got unexpected result ret %#x, length %#x, test %u.\n", ret, length, test);
+ length = 0xdeadbeef;
+ ret = pRtlGetExtendedContextLength2(flags, &length, 3);
+ ok(!ret && length == expected_length_xstate - sizeof(YMMCONTEXT),
+ "Got unexpected result ret %#x, length %#x, test %u.\n", ret, length, test);
- length = 0xdeadbeef;
- ret = pRtlGetExtendedContextLength2(flags, &length, 3);
- ok(!ret && length == expected_length_xstate - sizeof(YMMCONTEXT),
- "Got unexpected result ret %#x, length %#x, test %u.\n", ret, length, test);
+ length = 0xdeadbeef;
+ ret = pRtlGetExtendedContextLength2(flags, &length, 4);
+ ok(!ret && length == expected_length_xstate,
+ "Got unexpected result ret %#x, length %#x, test %u.\n", ret, length, test);
+ }
- length = 0xdeadbeef;
- ret = pRtlGetExtendedContextLength2(flags, &length, 4);
- ok(!ret && length == expected_length_xstate,
- "Got unexpected result ret %#x, length %#x, test %u.\n", ret, length, test);
+ pRtlGetExtendedContextLength(flags, &length);
+ SetLastError(0xdeadbeef);
+ bret = pInitializeContext(NULL, flags, NULL, &length2);
+ ok(!bret && length2 == length && GetLastError() == ERROR_INSUFFICIENT_BUFFER,
+ "Got unexpected bret %#x, length2 %#x, GetLastError() %u, flags %#x.\n",
+ bret, length2, GetLastError(), flags);
+
+ SetLastError(0xdeadbeef);
+ context = (void *)0xdeadbeef;
+ length2 = length - 1;
+ bret = pInitializeContext(context_buffer, flags, &context, &length2);
+ ok(!bret && GetLastError() == ERROR_INSUFFICIENT_BUFFER && length2 == length && context == (void *)0xdeadbeef,
+ "Got unexpected bret %#x, GetLastError() %u, length2 %#x, flags %#x.\n",
+ bret, GetLastError(), length2, flags);
+
+ SetLastError(0xdeadbeef);
+ memset(context_buffer, 0xcc, sizeof(context_buffer));
+ length2 = length + 1;
+ bret = pInitializeContext(context_buffer, flags, &context, &length2);
+ ok(bret && GetLastError() == 0xdeadbeef,
+ "Got unexpected bret %#x, GetLastError() %u, flags %#x.\n", bret, GetLastError(), flags);
+ ok(length2 == length, "Got unexpexted length %#x.\n", length);
+ ok((BYTE *)context == context_buffer, "Got unexpected context %p.\n", context);
+
+ context_flags = *(DWORD *)(context_buffer + context_arch[test].flags_offset);
+ ok(context_flags == flags, "Got unexpected ContextFlags %#x, flags %#x.\n", context_flags, flags);
+
+ context_ex = (CONTEXT_EX *)(context_buffer + context_arch[test].context_length);
+ ok(context_ex->Legacy.Offset == -(int)context_arch[test].context_length,
+ "Got unexpected Offset %d, flags %#x.\n", context_ex->Legacy.Offset, flags);
+ ok(context_ex->Legacy.Length == ((flags & 0x20) ? context_arch[test].context_length
+ : context_arch[test].legacy_length),
+ "Got unexpected Length %#x, flags %#x.\n", context_ex->Legacy.Length, flags);
+
+ expected_offset = (((ULONG_PTR)context + context_arch[test].context_length
+ + context_arch[test].context_ex_length + 63) & ~(ULONG64)63) - (ULONG_PTR)context
+ - context_arch[test].context_length;
+ ok(context_ex->XState.Offset == expected_offset,
+ "Got unexpected Offset %d, flags %#x.\n", context_ex->XState.Offset, flags);
+ ok(context_ex->XState.Length >= sizeof(XSTATE),
+ "Got unexpected Length %#x, flags %#x.\n", context_ex->XState.Length, flags);
+
+ ok(context_ex->All.Offset == -(int)context_arch[test].context_length,
+ "Got unexpected Offset %d, flags %#x.\n", context_ex->All.Offset, flags);
+ /* No extra 8 bytes in x64 CONTEXT_EX here. */
+ ok(context_ex->All.Length == context_arch[test].context_length
+ + context_ex->XState.Offset + context_ex->XState.Length,
+ "Got unexpected Length %#x, flags %#x.\n", context_ex->All.Length, flags);
+
+ xs = (XSTATE *)((BYTE *)context_ex + context_ex->XState.Offset);
+ ok(!xs->Mask, "Got unexpected Mask %s.\n", wine_dbgstr_longlong(xs->Mask));
+ ok(xs->CompactionMask == (compaction_enabled ? ((ULONG64)1 << 63) | enabled_features : 0),
+ "Got unexpected CompactionMask %s.\n", wine_dbgstr_longlong(xs->CompactionMask));
+ ok(!xs->Reserved[0], "Got unexpected Reserved[0] %s.\n", wine_dbgstr_longlong(xs->Reserved[0]));
+
+ if (pRtlGetExtendedContextLength2)
+ {
+ memset(context_buffer, 0xcc, sizeof(context_buffer));
+ pRtlGetExtendedContextLength2(flags, &length, 0);
+ SetLastError(0xdeadbeef);
+ memset(context_buffer, 0xcc, sizeof(context_buffer));
+ length2 = length;
+ bret = pInitializeContext2(context_buffer, flags, &context, &length2, 0);
+ ok(bret && GetLastError() == 0xdeadbeef,
+ "Got unexpected bret %#x, GetLastError() %u, flags %#x.\n", bret, GetLastError(), flags);
+ ok(length2 == length, "Got unexpexted length %#x.\n", length);
+ ok((BYTE *)context == context_buffer, "Got unexpected context %p.\n", context);
+
+ context_flags = *(DWORD *)(context_buffer + context_arch[test].flags_offset);
+ ok(context_flags == flags, "Got unexpected ContextFlags %#x, flags %#x.\n", context_flags, flags);
+
+ context_ex = (CONTEXT_EX *)(context_buffer + context_arch[test].context_length);
+ ok(context_ex->Legacy.Offset == -(int)context_arch[test].context_length,
+ "Got unexpected Offset %d, flags %#x.\n", context_ex->Legacy.Offset, flags);
+ ok(context_ex->Legacy.Length == ((flags & 0x20) ? context_arch[test].context_length
+ : context_arch[test].legacy_length),
+ "Got unexpected Length %#x, flags %#x.\n", context_ex->Legacy.Length, flags);
+
+ expected_offset = (((ULONG_PTR)context + context_arch[test].context_length
+ + context_arch[test].context_ex_length + 63) & ~(ULONG64)63) - (ULONG_PTR)context
+ - context_arch[test].context_length;
+ ok(context_ex->XState.Offset == expected_offset,
+ "Got unexpected Offset %d, flags %#x.\n", context_ex->XState.Offset, flags);
+ ok(context_ex->XState.Length == sizeof(XSTATE) - sizeof(YMMCONTEXT),
+ "Got unexpected Length %#x, flags %#x.\n", context_ex->XState.Length, flags);
+
+ ok(context_ex->All.Offset == -(int)context_arch[test].context_length,
+ "Got unexpected Offset %d, flags %#x.\n", context_ex->All.Offset, flags);
+ /* No extra 8 bytes in x64 CONTEXT_EX here. */
+ ok(context_ex->All.Length == context_arch[test].context_length
+ + context_ex->XState.Offset + context_ex->XState.Length,
+ "Got unexpected Length %#x, flags %#x.\n", context_ex->All.Length, flags);
+
+ xs = (XSTATE *)((BYTE *)context_ex + context_ex->XState.Offset);
+ ok(!xs->Mask, "Got unexpected Mask %s.\n", wine_dbgstr_longlong(xs->Mask));
+ ok(xs->CompactionMask == (compaction_enabled ? (ULONG64)1 << 63 : 0),
+ "Got unexpected CompactionMask %s.\n", wine_dbgstr_longlong(xs->CompactionMask));
+ ok(!xs->Reserved[0], "Got unexpected Reserved[0] %s.\n", wine_dbgstr_longlong(xs->Reserved[0]));
+ }
}
+ length = 0xdeadbeef;
+ ret = pRtlGetExtendedContextLength(context_arch[0].flag | context_arch[1].flag, &length);
+ ok(ret == STATUS_INVALID_PARAMETER && length == 0xdeadbeef, "Got unexpected result ret %#x, length %#x.\n",
+ ret, length);
+
if (0)
{
/* Crashes on Windows. */
pRtlGetExtendedContextLength(CONTEXT_FULL, NULL);
+ length = sizeof(context_buffer);
+ pInitializeContext(context_buffer, CONTEXT_FULL, NULL, &length);
+ pInitializeContext(context_buffer, CONTEXT_FULL, &context, NULL);
}
if (!(enabled_features & (1 << XSTATE_AVX)))
@@ -6307,6 +6590,7 @@ static void test_extended_context(void)
START_TEST(exception)
{
HMODULE hntdll = GetModuleHandleA("ntdll.dll");
+ HMODULE hkernel32 = GetModuleHandleA("kernel32.dll");
#if defined(__x86_64__)
HMODULE hmsvcrt = LoadLibraryA("msvcrt.dll");
#endif
@@ -6349,11 +6633,18 @@ START_TEST(exception)
X(RtlGetEnabledExtendedFeatures);
X(RtlGetExtendedContextLength);
X(RtlGetExtendedContextLength2);
+ X(RtlInitializeExtendedContext);
+ X(RtlInitializeExtendedContext2);
#undef X
- pIsWow64Process = (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"), "IsWow64Process");
+#define X(f) p##f = (void*)GetProcAddress(hkernel32, #f)
+ X(IsWow64Process);
if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
+ X(InitializeContext);
+ X(InitializeContext2);
+#undef X
+
if (pRtlAddVectoredExceptionHandler && pRtlRemoveVectoredExceptionHandler)
have_vectored_api = TRUE;
else
diff --git a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec
index 45024a3a8da..163e041065f 100644
--- a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec
+++ b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec
@@ -1122,6 +1122,8 @@
@ stdcall RtlInitUnicodeString(ptr wstr)
@ stdcall RtlInitUnicodeStringEx(ptr wstr)
@ stdcall RtlInitializeBitMap(ptr ptr long)
+@ stdcall RtlInitializeExtendedContext(ptr long ptr)
+@ stdcall RtlInitializeExtendedContext2(ptr long ptr int64)
@ stdcall RtlInitializeGenericTable(ptr ptr ptr ptr ptr)
@ stdcall RtlInitializeGenericTableAvl(ptr ptr ptr ptr ptr)
@ stub RtlInitializeRangeList
diff --git a/include/ddk/wdm.h b/include/ddk/wdm.h
index 0c641fa4122..703929074fc 100644
--- a/include/ddk/wdm.h
+++ b/include/ddk/wdm.h
@@ -1837,6 +1837,8 @@ BOOLEAN WINAPI PsGetVersion(ULONG*,ULONG*,ULONG*,UNICODE_STRING*);
NTSTATUS WINAPI PsTerminateSystemThread(NTSTATUS);
#if defined(__x86_64__) || defined(__i386__)
+NTSTATUS WINAPI RtlInitializeExtendedContext(void*,ULONG,CONTEXT_EX**);
+NTSTATUS WINAPI RtlInitializeExtendedContext2(void*,ULONG,CONTEXT_EX**,ULONG64);
ULONG64 WINAPI RtlGetEnabledExtendedFeatures(ULONG64);
NTSTATUS WINAPI RtlGetExtendedContextLength(ULONG,ULONG*);
NTSTATUS WINAPI RtlGetExtendedContextLength2(ULONG,ULONG*,ULONG64);
diff --git a/include/winbase.h b/include/winbase.h
index f2177ada1e4..9957cd43bb6 100644
--- a/include/winbase.h
+++ b/include/winbase.h
@@ -2379,6 +2379,8 @@ WINBASEAPI BOOL WINAPI HeapWalk(HANDLE,LPPROCESS_HEAP_ENTRY);
WINBASEAPI BOOL WINAPI InitAtomTable(DWORD);
WINADVAPI BOOL WINAPI InitializeAcl(PACL,DWORD,DWORD);
WINBASEAPI VOID WINAPI InitializeConditionVariable(PCONDITION_VARIABLE);
+WINBASEAPI BOOL WINAPI InitializeContext(void *,DWORD,CONTEXT **,DWORD *);
+WINBASEAPI BOOL WINAPI InitializeContext2(void *,DWORD,CONTEXT **,DWORD *,ULONG64);
WINBASEAPI void WINAPI InitializeCriticalSection(CRITICAL_SECTION *lpCrit);
WINBASEAPI BOOL WINAPI InitializeCriticalSectionAndSpinCount(CRITICAL_SECTION *,DWORD);
WINBASEAPI BOOL WINAPI InitializeCriticalSectionEx(CRITICAL_SECTION *,DWORD,DWORD);
--
2.26.2
More information about the wine-devel
mailing list