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 e8d1f83adc6..2d6ddfef3c3 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 dc6a4b34a73..29a68271cdd 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 @@ -6024,6 +6031,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) @@ -6032,14 +6040,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); @@ -6070,9 +6072,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) { @@ -6145,8 +6147,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[] = { @@ -6155,24 +6159,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; @@ -6186,6 +6200,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); @@ -6211,7 +6233,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) @@ -6227,6 +6249,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; @@ -6238,6 +6387,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; } @@ -6247,39 +6421,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, ~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, 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, 7); - 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); - 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); + 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); - 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); + 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); - 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); + context_flags = *(DWORD *)(context_buffer + context_arch[test].flags_offset); + ok(context_flags == flags, "Got unexpected ContextFlags %#x, flags %#x.\n", context_flags, flags); - 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); + 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))) @@ -6313,6 +6596,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 @@ -6355,11 +6639,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);