Signed-off-by: Paul Gofman pgofman@codeweavers.com --- dlls/ntdll/tests/virtual.c | 67 ++++++++++++++++++++++++++++++++++++ programs/wineboot/wineboot.c | 59 +++++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+)
diff --git a/dlls/ntdll/tests/virtual.c b/dlls/ntdll/tests/virtual.c index beab744178a..4a0a4a6b8e5 100644 --- a/dlls/ntdll/tests/virtual.c +++ b/dlls/ntdll/tests/virtual.c @@ -516,9 +516,34 @@ static void test_NtMapViewOfSection(void) CloseHandle(process); }
+#define SUPPORTED_XSTATE_FEATURES ((1 << XSTATE_LEGACY_FLOATING_POINT) | (1 << XSTATE_LEGACY_SSE) | (1 << XSTATE_AVX)) + static void test_user_shared_data(void) { + struct old_xstate_configuration + { + ULONG64 EnabledFeatures; + ULONG Size; + ULONG OptimizedSave:1; + ULONG CompactionEnabled:1; + XSTATE_FEATURE Features[MAXIMUM_XSTATE_FEATURES]; + }; + + static const ULONG feature_offsets[] = + { + 0, + 160, /*offsetof(XMM_SAVE_AREA32, XmmRegisters)*/ + 512 /* sizeof(XMM_SAVE_AREA32) */ + offsetof(XSTATE, YmmContext), + }; + static const ULONG feature_sizes[] = + { + 160, + 256, /*sizeof(M128A) * 16 */ + sizeof(YMMCONTEXT), + }; const KSHARED_USER_DATA *user_shared_data = (void *)0x7ffe0000; + XSTATE_CONFIGURATION xstate = user_shared_data->XState; + unsigned int i;
ok(user_shared_data->NumberOfPhysicalPages == sbi.MmNumberOfPhysicalPages, "Got number of physical pages %#x, expected %#x.\n", @@ -534,6 +559,48 @@ static void test_user_shared_data(void) ok(user_shared_data->ActiveGroupCount == 1 || broken(!user_shared_data->ActiveGroupCount) /* before Win7 */, "Got unexpected ActiveGroupCount %u.\n", user_shared_data->ActiveGroupCount); + + if (!xstate.EnabledFeatures) + { + struct old_xstate_configuration *xs_old + = (struct old_xstate_configuration *)((char *)user_shared_data + 0x3e0); + + if (!xs_old->EnabledFeatures) + { + skip("XState features are not supported.\n"); + return; + } + + memset(&xstate, 0, sizeof(xstate)); + xstate.EnabledFeatures = xstate.EnabledVolatileFeatures = xs_old->EnabledFeatures; + memcpy(&xstate.Size, &xs_old->Size, sizeof(*xs_old) - offsetof(struct old_xstate_configuration, Size)); + for (i = 0; i < 3; ++i) + xstate.AllFeatures[i] = xs_old->Features[i].Size; + xstate.AllFeatureSize = 512 + sizeof(XSTATE); + } + + trace("XState EnabledFeatures %s.\n", wine_dbgstr_longlong(xstate.EnabledFeatures)); + ok((xstate.EnabledFeatures & SUPPORTED_XSTATE_FEATURES) == SUPPORTED_XSTATE_FEATURES, + "Got unexpected EnabledFeatures %s.\n", wine_dbgstr_longlong(xstate.EnabledFeatures)); + ok((xstate.EnabledVolatileFeatures & SUPPORTED_XSTATE_FEATURES) == xstate.EnabledFeatures, + "Got unexpected EnabledVolatileFeatures %s.\n", wine_dbgstr_longlong(xstate.EnabledVolatileFeatures)); + ok(xstate.Size >= 512 + sizeof(XSTATE), "Got unexpected Size %u.\n", xstate.Size); + if (xstate.CompactionEnabled) + ok(xstate.OptimizedSave, "Got zero OptimizedSave with compaction enabled.\n"); + ok(!xstate.AlignedFeatures, "Got unexpected AlignedFeatures %s.\n", + wine_dbgstr_longlong(xstate.AlignedFeatures)); + ok(xstate.AllFeatureSize >= 512 + sizeof(XSTATE), "Got unexpected AllFeatureSize %u.\n", + xstate.AllFeatureSize); + + for (i = 0; i < ARRAY_SIZE(feature_sizes); ++i) + { + ok(xstate.AllFeatures[i] == feature_sizes[i], "Got unexpected AllFeatures[%u] %u, expected %u.\n", i, + xstate.AllFeatures[i], feature_sizes[i]); + ok(xstate.Features[i].Size == feature_sizes[i], "Got unexpected Features[%u].Size %u, expected %u.\n", i, + xstate.Features[i].Size, feature_sizes[i]); + ok(xstate.Features[i].Offset == feature_offsets[i], "Got unexpected Features[%u].Offset %u, expected %u.\n", + i, xstate.Features[i].Offset, feature_offsets[i]); + } }
START_TEST(virtual) diff --git a/programs/wineboot/wineboot.c b/programs/wineboot/wineboot.c index 902f6af042e..2f8b7169cf6 100644 --- a/programs/wineboot/wineboot.c +++ b/programs/wineboot/wineboot.c @@ -191,6 +191,63 @@ static DWORD set_reg_value_dword( HKEY hkey, const WCHAR *name, DWORD value ) return RegSetValueExW( hkey, name, 0, REG_DWORD, (const BYTE *)&value, sizeof(value) ); }
+#if defined(__i386__) || defined(__x86_64__) + +static void initialize_xstate_features(struct _KUSER_SHARED_DATA *data) +{ + XSTATE_CONFIGURATION *xstate = &data->XState; + unsigned int i; + int regs[4]; + + if (!data->ProcessorFeatures[PF_AVX_INSTRUCTIONS_AVAILABLE]) + return; + + __cpuidex(regs, 0, 0); + + TRACE("Max cpuid level %#x.\n", regs[0]); + if (regs[0] < 0xd) + return; + + __cpuidex(regs, 1, 0); + TRACE("CPU features %#x, %#x, %#x, %#x.\n", regs[0], regs[1], regs[2], regs[3]); + if (!(regs[2] & (0x1 << 27))) /* xsave OS enabled */ + return; + + __cpuidex(regs, 0xd, 0); + TRACE("XSAVE details %#x, %#x, %#x, %#x.\n", regs[0], regs[1], regs[2], regs[3]); + if (!(regs[0] & XSTATE_AVX)) + return; + + xstate->EnabledFeatures = (1 << XSTATE_LEGACY_FLOATING_POINT) | (1 << XSTATE_LEGACY_SSE) | (1 << XSTATE_AVX); + xstate->EnabledVolatileFeatures = xstate->EnabledFeatures; + xstate->Size = sizeof(XSAVE_FORMAT) + sizeof(XSTATE); + xstate->AllFeatureSize = regs[1]; + xstate->AllFeatures[0] = offsetof(XSAVE_FORMAT, XmmRegisters); + xstate->AllFeatures[1] = sizeof(M128A) * 16; + xstate->AllFeatures[2] = sizeof(YMMCONTEXT); + + for (i = 0; i < 3; ++i) + xstate->Features[i].Size = xstate->AllFeatures[i]; + + xstate->Features[1].Offset = xstate->Features[0].Size; + xstate->Features[2].Offset = sizeof(XSAVE_FORMAT) + offsetof(XSTATE, YmmContext); + + __cpuidex(regs, 0xd, 1); + xstate->OptimizedSave = regs[0] & 1; + xstate->CompactionEnabled = !!(regs[0] & 2); + + __cpuidex(regs, 0xd, 2); + TRACE("XSAVE feature 2 %#x, %#x, %#x, %#x.\n", regs[0], regs[1], regs[2], regs[3]); +} + +#else + +static void initialize_xstate_features(struct _KUSER_SHARED_DATA *data) +{ +} + +#endif + static void create_user_shared_data(void) { struct _KUSER_SHARED_DATA *data; @@ -276,6 +333,8 @@ static void create_user_shared_data(void) data->ActiveProcessorCount = NtCurrentTeb()->Peb->NumberOfProcessors; data->ActiveGroupCount = 1;
+ initialize_xstate_features( data ); + UnmapViewOfFile( data ); }