Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=58335
This should help to demonstrate the issue in above bug and probably add a way check to such an issue in gitlab.
-- v6: gitlab: Add test for non-avx code path in __wine_syscall_dispatcher. ntdll: Add environment to override cpuid for debugging and test.
From: Bernhard Übelacker bernhardu@mailbox.org
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=58335 --- dlls/ntdll/tests/virtual.c | 48 ++++++++++++++++++++++++++++++++++++++ dlls/ntdll/unix/system.c | 32 ++++++++++++++++++++++++- 2 files changed, 79 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/tests/virtual.c b/dlls/ntdll/tests/virtual.c index c48652f0f65..2bfb800de74 100644 --- a/dlls/ntdll/tests/virtual.c +++ b/dlls/ntdll/tests/virtual.c @@ -3209,6 +3209,48 @@ static void test_exec_memory_writes(void) RtlRemoveVectoredExceptionHandler( handler ); }
+static void test_cpuid_child(void) +{ +#if defined(__x86_64__) && !defined(__arm64ec__) + HMODULE module = GetModuleHandleW( L"ntdll.dll" ); + NTSTATUS (WINAPI *pNtClose)(HANDLE); + int val[] = {0xabcdef00, 0x12345678, 0xfedcba00, 0x87654321}; + + __asm__ __volatile__ ( "movaps %0,%%xmm6" : : "m" (val) ); + /* just some call to get through __wine_syscall_dispatcher */ + pNtClose = (void *)GetProcAddress( module, "NtClose" ); + pNtClose(INVALID_HANDLE_VALUE); + __asm__ __volatile__ ( "movaps %%xmm6,%0" : "=m" (val) ); + + ok(val[0] == 0xabcdef00 && val[1] == 0x12345678 && val[2] == 0xfedcba00 && val[3] == 0x87654321, + "register xmm6 has unexpected values 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", val[0], val[1], val[2], val[3]); +#endif +} + +static void test_cpuid(void) +{ +#if defined(__x86_64__) && !defined(__aarch64__) + PROCESS_INFORMATION info; + STARTUPINFOA startup; + char **argv; + char path_name[MAX_PATH]; + DWORD ret; + + winetest_get_mainargs(&argv); + memset(&startup, 0, sizeof(startup)); + startup.cb = sizeof(startup); + sprintf(path_name, "%s %s cpuid", argv[0], argv[1]); + + ret = CreateProcessA(NULL, path_name, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info); + ok(ret, "Failed to create target process.\n"); + + wait_child_process(info.hProcess); + + CloseHandle(info.hProcess); + CloseHandle(info.hThread); +#endif +} + START_TEST(virtual) { HMODULE mod; @@ -3224,6 +3266,11 @@ START_TEST(virtual) Sleep(5000); /* spawned process runs for at most 5 seconds */ return; } + if (!strcmp(argv[2], "cpuid")) + { + test_cpuid_child(); + return; + } return; }
@@ -3262,4 +3309,5 @@ START_TEST(virtual) test_query_region_information(); test_query_image_information(); test_exec_memory_writes(); + test_cpuid(); } diff --git a/dlls/ntdll/unix/system.c b/dlls/ntdll/unix/system.c index e486da40691..431d9b808b1 100644 --- a/dlls/ntdll/unix/system.c +++ b/dlls/ntdll/unix/system.c @@ -79,6 +79,9 @@ #include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(ntdll); +#if defined(__i386__) || defined(__x86_64__) +WINE_DECLARE_DEBUG_CHANNEL(cpuid); +#endif
#pragma pack(push,1)
@@ -321,11 +324,34 @@ void copy_xstate( XSAVE_AREA_HEADER *dst, XSAVE_AREA_HEADER *src, UINT64 mask ) } }
-static inline void do_cpuid( unsigned int ax, unsigned int cx, unsigned int *p ) +static inline void do_cpuid_( unsigned int ax, unsigned int cx, unsigned int *p ) { __asm__ ( "cpuid" : "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3]) : "a" (ax), "c" (cx) ); }
+static inline void do_cpuid( unsigned int ax, unsigned int cx, unsigned int *p ) +{ + char buf[30]; + char *override; + + memset(p, 0, sizeof(*p)*4); + do_cpuid_(ax, cx, p); + TRACE_(cpuid)("cpuid returned WINE_CPUID_%08x_%08x=%08x_%08x_%08x_%08x\n", + ax, cx, p[0], p[1], p[2], p[3]); + + snprintf(buf, sizeof(buf), "WINE_CPUID_%08x_%08x", ax, cx); + override = getenv(buf); + if (override && strlen(override) == 35) + { + sscanf(override, "%08x", &p[0]); + sscanf(override+9, "%08x", &p[1]); + sscanf(override+18, "%08x", &p[2]); + sscanf(override+27, "%08x", &p[3]); + ERR_(cpuid)("overriding with WINE_CPUID_%08x_%08x=%08x_%08x_%08x_%08x\n", + ax, cx, p[0], p[1], p[2], p[3]); + } +} + static inline UINT64 do_xgetbv( unsigned int cx ) { UINT low, high; @@ -432,6 +458,8 @@ static void init_xstate_features( XSTATE_CONFIGURATION *xstate ) ULONG64 supported_mask; unsigned int i, off, regs[4];
+ TRACE_(cpuid)("init_xstate_features reached.\n"); + do_cpuid( 0x0000000d, 0, regs ); TRACE( "XSAVE details %#x, %#x, %#x, %#x.\n", regs[0], regs[1], regs[2], regs[3] ); supported_mask = ((ULONG64)regs[3] << 32) | regs[0]; @@ -479,6 +507,8 @@ void init_shared_data_cpuinfo( KUSER_SHARED_DATA *data ) BOOLEAN *features = data->ProcessorFeatures; unsigned int regs[4];
+ TRACE_(cpuid)("init_shared_data_cpuinfo reached.\n"); + features[PF_FASTFAIL_AVAILABLE] = TRUE; features[PF_COMPARE_EXCHANGE_DOUBLE] = TRUE;
From: Bernhard Übelacker bernhardu@mailbox.org
--- tools/gitlab/test.yml | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+)
diff --git a/tools/gitlab/test.yml b/tools/gitlab/test.yml index 2b03a05264f..2bba830edcb 100644 --- a/tools/gitlab/test.yml +++ b/tools/gitlab/test.yml @@ -59,6 +59,34 @@ CI_COMMIT_MESSAGE: "" GITLAB_USER_NAME: ""
+test-linux-64-non-avx: + extends: .wine-test + variables: + INCLUDE_TESTS: "ntdll:virtual" + rules: + - if: $CI_PIPELINE_SOURCE == 'merge_request_event' + needs: + - job: build-linux + script: + - export WINETEST_COLOR=1 + # Pentium(R) Dual-Core CPU T4500 @ 2.30GHz + - export WINE_CPUID_00000000_00000000=0000000d_756e6547_6c65746e_49656e69 + - export WINE_CPUID_00000001_00000000=0001067a_01020800_0c00e39d_bfebfbff + - export WINE_CPUID_00000007_00000000=00000000_00000000_00000000_00000000 + - export WINE_CPUID_0000000d_00000000=00000003_00000240_00000240_00000000 + - export WINE_CPUID_80000000_00000000=80000008_00000000_00000000_00000000 + - export WINE_CPUID_80000001_00000000=00000000_00000000_00000001_20100800 + - export WINE_CPUID_80000002_00000000=746e6550_286d7569_44202952_2d6c6175 + - export WINE_CPUID_80000003_00000000=65726f43_55504320_20202020_54202020 + - export WINE_CPUID_80000004_00000000=30303534_20402020_30332e32_007a4847 + - wine usr/local/lib/wine/x86_64-windows/winetest.exe -q -q -o - -J winetest.xml $INCLUDE_TESTS + artifacts: + when: always + paths: + - winetest.xml + reports: + junit: winetest.xml + test-linux-64: extends: .wine-test variables:
v3/v4/v5/v6: - Really build the test just on x86_64.
On Fri Jul 18 21:47:25 2025 +0000, Bernhard Übelacker wrote:
I found following pre-defined macros. Still strange arm64ec has x86_64 ...
$ clang -target arm64ec-windows -dM -E -x c /dev/null | grep -E "__x86_64__|arm.*ec" #define __arm64ec__ 1 #define __x86_64__ 1
It needs to use the x86_64 versions of various data structures, so it can interoperate with actual emulated x86_64 code.
MSVC doesn't permit inline asm outside i386, and most or all intrinsics are available (even the SSE/AVX ones work, though the ones that don't correspond to ARM instructions are slow), so there's little or nothing that'd work as actual x86_64 under MSVC but fail as arm64ec.
But yes, sucks for us. But we're not really Microsoft's target audience, are we?
On Fri Jul 18 12:51:01 2025 +0000, Bernhard Übelacker wrote:
Thanks for looking into it. This is not intended for users, more for developers trying to reproduce bug reports. (Except enabling the cpuid debug channel and providing the values to the developer.) The ARCH_SET_CPUID looks interesting, I will try to generalize this, thanks.
We could use https://github.com/twosigma/libvirtcpuid, seems it's commonly used in tandem with CRIU.