Takes advantage of linux's ID register emulation. The msr instruction is manually assembled to support older compilers and those that disallow reading e.g. SVE ID registers if unsupported by the target, even though they RAZ if unsupported.
From: Billy Laws blaws05@gmail.com
--- dlls/ntdll/unix/registry.c | 32 ++++++++++++++++++++++++++++++++ dlls/ntdll/unix/unix_private.h | 2 ++ 2 files changed, 34 insertions(+)
diff --git a/dlls/ntdll/unix/registry.c b/dlls/ntdll/unix/registry.c index e19414bfa86..666c2942335 100644 --- a/dlls/ntdll/unix/registry.c +++ b/dlls/ntdll/unix/registry.c @@ -68,6 +68,38 @@ NTSTATUS open_hkcu_key( const char *path, HANDLE *key ) return NtCreateKey( key, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ); }
+NTSTATUS create_key_recursive( HANDLE *key, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, + ULONG index, const UNICODE_STRING *class, ULONG options, ULONG *dispos ) +{ + NTSTATUS status; + HANDLE own_key; + OBJECT_ATTRIBUTES own_attr; + UNICODE_STRING own_name; + DWORD len; + + status = NtCreateKey( key, access, attr, index, class, options, dispos ); + if (!status || status != STATUS_OBJECT_NAME_NOT_FOUND) return status; + + own_attr = *attr; + own_attr.ObjectName = &own_name; + own_name = *attr->ObjectName; + len = own_name.Length / sizeof(WCHAR); + + while (len && own_name.Buffer[len - 1] != '\') len--; + if (!len--) return STATUS_OBJECT_PATH_INVALID; + + own_name.Length = len * sizeof(WCHAR); + status = create_key_recursive( &own_key, access, &own_attr, index, class, options & ~REG_OPTION_CREATE_LINK, dispos ); + if (status) return status; + + own_attr.RootDirectory = own_key; + own_name.Buffer += len + 1; + own_name.Length = attr->ObjectName->Length - own_name.Length - sizeof(WCHAR); + + status = NtCreateKey( key, access, &own_attr, index, class, options, dispos ); + NtClose(own_key); + return status; +}
/****************************************************************************** * NtCreateKey (NTDLL.@) diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index ee5630e76f1..517af815de7 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -321,6 +321,8 @@ extern NTSTATUS get_thread_wow64_context( HANDLE handle, void *ctx, ULONG size ) extern NTSTATUS set_thread_wow64_context( HANDLE handle, const void *ctx, ULONG size ); extern void fill_vm_counters( VM_COUNTERS_EX *pvmi, int unix_pid ); extern NTSTATUS open_hkcu_key( const char *path, HANDLE *key ); +extern NTSTATUS create_key_recursive( HANDLE *key, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, + ULONG index, const UNICODE_STRING *class, ULONG options, ULONG *dispos );
extern NTSTATUS sync_ioctl( HANDLE file, ULONG code, void *in_buffer, ULONG in_size, void *out_buffer, ULONG out_size );
From: Billy Laws blaws05@gmail.com
Takes advantage of linux's ID register emulation. The msr instruction is manually assembled to support older compilers and those that disallow reading e.g. SVE ID registers if unsupported by the target, even though they RAZ if unsupported. --- dlls/ntdll/unix/system.c | 95 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+)
diff --git a/dlls/ntdll/unix/system.c b/dlls/ntdll/unix/system.c index f87c9b09124..eadf5a61e31 100644 --- a/dlls/ntdll/unix/system.c +++ b/dlls/ntdll/unix/system.c @@ -1309,6 +1309,96 @@ static void init_tsc_frequency(void)
#endif
+#ifdef __aarch64__ +#ifdef linux + +static NTSTATUS fill_arm64_id_reg_keys(void) +{ + static const char processor_key[] = "\Registry\Machine\Hardware\Description\System\CentralProcessor\%u"; + static const char midr_el1_path[] = "/sys/devices/system/cpu/cpu%u/regs/identification/midr_el1"; + static const char reg_value_name[] = "CP %04X"; + NTSTATUS status = STATUS_SUCCESS; + OBJECT_ATTRIBUTES attr; + UNICODE_STRING name; + WCHAR bufferW[256]; + char buffer[256]; + unsigned int i; + + InitializeObjectAttributes( &attr, &name, OBJ_CASE_INSENSITIVE, 0, NULL ); + for (i = 0; i < peb->NumberOfProcessors; i++) + { + unsigned long long value; + HANDLE key; + FILE *fp; + + snprintf( buffer, sizeof(buffer), processor_key, i ); + ascii_to_unicode( bufferW, buffer, strlen(buffer) + 1 ); + init_unicode_string( &name, bufferW ); + if ((status = create_key_recursive( &key, KEY_ALL_ACCESS, &attr, 0, NULL, REG_OPTION_VOLATILE, NULL ))) + return status; + + /* MIDR_EL1 can vary across cores, so read it from sysfs. */ + snprintf( buffer, sizeof(buffer), midr_el1_path, i ); + if ((fp = fopen( buffer, "r" ))) + { + fscanf( fp, "%llx", &value ); + fclose( fp ); + snprintf( buffer, sizeof(buffer), reg_value_name, 0x4000 ); + ascii_to_unicode( bufferW, buffer, strlen(buffer) + 1 ); + init_unicode_string( &name, bufferW ); + NtSetValueKey( key, &name, 0, REG_QWORD, &value, sizeof(value) ); + } + +#define STR(a) #a +#define READ_ID_REG(reg_id) \ + snprintf( buffer, sizeof(buffer), reg_value_name, reg_id ); \ + ascii_to_unicode( bufferW, buffer, strlen(buffer) + 1 ); \ + init_unicode_string( &name, bufferW ); \ + /* mrs x0, #reg_id */ \ + __asm__ __volatile__( ".inst " STR(0xd5300000 | reg_id << 5) "\n\t" \ + "mov %0, x0" : "=r"(value) :: "x0" ); \ + NtSetValueKey( key, &name, 0, REG_QWORD, &value, sizeof(UINT64) ) + + /* Linux traps reads to these ID registers and emulates them. They do not vary across cores, + * if the kernel doesn't support a specific ID register it will read as zero. */ + READ_ID_REG( 0x4020 ); /* ID_AA64PFR0_EL1 */ + READ_ID_REG( 0x4021 ); /* ID_AA64PFR1_EL1 */ + READ_ID_REG( 0x4024 ); /* ID_AA64ZFR0_EL1 */ + READ_ID_REG( 0x4025 ); /* ID_AA64SMFR0_EL1 */ + READ_ID_REG( 0x4028 ); /* ID_AA64DFR0_EL1 */ + READ_ID_REG( 0x4029 ); /* ID_AA64DFR1_EL1 */ + READ_ID_REG( 0x402C ); /* ID_AA64AFR0_EL1 */ + READ_ID_REG( 0x402D ); /* ID_AA64AFR1_EL1 */ + READ_ID_REG( 0x4030 ); /* ID_AA64ISAR0_EL1 */ + READ_ID_REG( 0x4031 ); /* ID_AA64ISAR1_EL1 */ + READ_ID_REG( 0x4032 ); /* ID_AA64ISAR2_EL1 */ + READ_ID_REG( 0x4038 ); /* ID_AA64MMFR0_EL1 */ + READ_ID_REG( 0x4039 ); /* ID_AA64MMFR1_EL1 */ + READ_ID_REG( 0x403A ); /* ID_AA64MMFR2_EL1 */ + READ_ID_REG( 0x5801 ); /* CTR_EL0 */ + /* Windows also creates keys for SCTLR_EL1, ACTLR_EL1, TTBR0_EL1 and MAIR_EL1, but these are + * inaccessible under linux so leave them unpopulated. */ + +#undef READ_ID_REG +#undef STR + NtClose( key ); + } + + return status; +} + +#else + +static void fill_arm64_id_reg_keys(void) +{ + FIXME("stub\n"); + return STATUS_NOT_IMPLEMENTED; +} + +#endif +#endif + + /****************************************************************** * init_cpu_info * @@ -1368,6 +1458,11 @@ void init_cpu_info(void) logical_proc_info_ex_alloc_size = logical_proc_info_ex_size; } init_tsc_frequency(); + +#ifdef __aarch64__ + if ((status = fill_arm64_id_reg_keys())) + ERR( "Failed to populate ARM64 ID register registry keys, status %#x.\n", status ); +#endif }
static NTSTATUS create_cpuset_info(SYSTEM_CPU_SET_INFORMATION *info)
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=147599
Your paranoid android.
=== debian11b (64 bit WoW report) ===
dinput: hotplug.c:194: Test failed: 0x500: GetDeviceState returned 0 hid.c:744: Test failed: CreateFile failed, error 3 hid.c:746: Test failed: IOCTL_WINETEST_CREATE_DEVICE failed, last error 6
hid: device.c:123: Test failed: Failed to open L"\\?\hid#vid_1209&pid_0001#0&0000&0#{4d1e55b2-f16f-11cf-88cb-001111000030}", error 3. device.c:123: Test failed: Failed to open L"\\?\hid#vid_1209&pid_0001&col01#256&wine test&0&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}", error 3. device.c:123: Test failed: Failed to open L"\\?\hid#vid_1209&pid_0001&col02#256&wine test&0&0&0001#{4d1e55b2-f16f-11cf-88cb-001111000030}", error 3. device.c:123: Test failed: Failed to open L"\\?\hid#vid_845e&pid_0001#0&0000&0&0&0#{4d1e55b2-f16f-11cf-88cb-001111000030}", error 3. device.c:123: Test failed: Failed to open L"\\?\hid#vid_845e&pid_0002#0&0000&0&0&0#{4d1e55b2-f16f-11cf-88cb-001111000030}", error 3. device.c:170: Test failed: got error 3 device.c:173: Test failed: Failed to get preparsed data(0x6) device.c:175: Test failed: Failed to get Caps(0xc0110001) device.c:170: Test failed: got error 3 device.c:173: Test failed: Failed to get preparsed data(0x6) device.c:175: Test failed: Failed to get Caps(0xc0110001) device.c:170: Test failed: got error 3 device.c:173: Test failed: Failed to get preparsed data(0x6) device.c:175: Test failed: Failed to get Caps(0xc0110001) device.c:170: Test failed: got error 3 device.c:173: Test failed: Failed to get preparsed data(0x6) device.c:175: Test failed: Failed to get Caps(0xc0110001) device.c:170: Test failed: got error 3 device.c:173: Test failed: Failed to get preparsed data(0x6) device.c:175: Test failed: Failed to get Caps(0xc0110001) device.c:170: Test failed: got error 3 device.c:173: Test failed: Failed to get preparsed data(0x6) device.c:175: Test failed: Failed to get Caps(0xc0110001) device.c:319: Test failed: Failed to get product string(0x6) device.c:323: Test failed: Failed to get preparsed data(0x6) device.c:325: Test failed: Failed to get Caps(0xc0110001) device.c:170: Test failed: got error 3 device.c:173: Test failed: Failed to get preparsed data(0x6) device.c:175: Test failed: Failed to get Caps(0xc0110001) device.c:170: Test failed: got error 3 device.c:173: Test failed: Failed to get preparsed data(0x6) device.c:175: Test failed: Failed to get Caps(0xc0110001) device.c:170: Test failed: got error 3 device.c:173: Test failed: Failed to get preparsed data(0x6) device.c:175: Test failed: Failed to get Caps(0xc0110001) device.c:170: Test failed: got error 3 device.c:173: Test failed: Failed to get preparsed data(0x6) device.c:175: Test failed: Failed to get Caps(0xc0110001) device.c:170: Test failed: got error 3 device.c:173: Test failed: Failed to get preparsed data(0x6) device.c:175: Test failed: Failed to get Caps(0xc0110001) device.c:170: Test failed: got error 3 device.c:173: Test failed: Failed to get preparsed data(0x6) device.c:175: Test failed: Failed to get Caps(0xc0110001) device.c:405: Test failed: Failed to get product string(0x6) device.c:409: Test failed: Failed to get preparsed data(0x6) device.c:411: Test failed: Failed to get Caps(0xc0110001)
user32: input.c:2206: Test failed: got 0 messages input.c:2216: Test failed: got 0 messages input.c:1933: Test failed: expected non-zero input.c:1939: Test failed: expected -1, got 0 input.c:1940: Test failed: expected 122, got -559038737 input.c:1941: Test failed: expected non-zero input.c:1945: Test failed: expected non-zero input.c:2080: Test failed: expected non-zero
This should be done in wineboot, where we set the rest of the CPU registry keys.
On Wed Aug 7 20:44:16 2024 +0000, Alexandre Julliard wrote:
This should be done in wineboot, where we set the rest of the CPU registry keys.
I did this in wineboot originally, however moved it to the Unix side because there's no way to read the per core midr otherwise. The ID instruction emulation is also Linux specific, and e.g. windows will sigill on them instead of emulating their results, hence windows must be populating these keys in the kernel. I could add a wine specific side channel to pass this register values to wine boot but I don't really see a benefit
On Wed Aug 7 20:44:16 2024 +0000, Billy Laws wrote:
I did this in wineboot originally, however moved it to the Unix side because there's no way to read the per core midr otherwise. The ID instruction emulation is also Linux specific, and e.g. windows will sigill on them instead of emulating their results, hence windows must be populating these keys in the kernel. I could add a wine specific side channel to pass this register values to wine boot but I don't really see a benefit
I believe we already have the necessary information in the SMBIOS data.
On Wed Aug 7 20:55:20 2024 +0000, Alexandre Julliard wrote:
I believe we already have the necessary information in the SMBIOS data.
This is not the case, there's no way to get the per-core/package variant and ignoring that it seems pointless to go back and forth between a string for e.g. vendor id (which can vary between packages also) all to reconstruct a register that can easily be accessed directly. I think in general though it doesn't really seem like linux specific code is put in wineboot, so it would necessitate some way to pass the ID registers from the Unix side either way?
On Wed Aug 7 21:26:39 2024 +0000, Billy Laws wrote:
This is not the case, there's no way to get the per-core/package variant and ignoring that it seems pointless to go back and forth between a string for e.g. vendor id (which can vary between packages also) all to reconstruct a register that can easily be accessed directly. I think in general though it doesn't really seem like linux specific code is put in wineboot, so it would necessitate some way to pass the ID registers from the Unix side either way? Infact it seems like the ID register emulation itself is optional on Linux and I should really be checking for the CPUID hwcap before using it
We don't set the variant per-core but that's easy to fix, if it turns out to be necessary.
On Wed Aug 7 21:25:14 2024 +0000, Alexandre Julliard wrote:
We don't set the variant per-core but that's easy to fix, if it turns out to be necessary.
I can fix that, but there's still the other mentioned issues. Aside from consistency, are there technical reasons to have this in wineboot?
On Wed Aug 7 21:56:09 2024 +0000, Billy Laws wrote:
I can fix that, but there's still the other mentioned issues. Aside from consistency, are there technical reasons to have this in wineboot? (To clarify what I mean about Linux emulating the instructions, `msr x0, ID_AA64PFR0_EL1` etc will sigill on macos and pre 4.11 Linux kernels)
So would adding a NtQuerySystemInformation class for features be reasonable here?
On Wed Aug 14 10:03:04 2024 +0000, Billy Laws wrote:
So would adding a NtQuerySystemInformation class for features be reasonable here?
I still think this would be better in wineboot. For unsupported registers/platforms, we can catch the exception and emulate it ourselves.
On Wed Aug 14 10:55:01 2024 +0000, Alexandre Julliard wrote:
I still think this would be better in wineboot. For unsupported registers/platforms, we can catch the exception and emulate it ourselves.
Emulating it would end up requiring an extra interface either way as not all of the features exposed in these regs are available through the windows feature APIs. I feel that if such an interface needs to exist at some point, it's preferable to be consistent and use that interface for everything rather than just macos or older Linux, doing that now for Linux would make it easier to support the rest.
On Wed Aug 14 11:23:17 2024 +0000, Billy Laws wrote:
Emulating it would end up requiring an extra interface either way as not all of the features exposed in these regs are available through the windows feature APIs. I feel that if such an interface needs to exist at some point, it's preferable to be consistent and use that interface for everything rather than just macos or older Linux, doing that now for Linux would make it easier to support the rest.
If you still think detection in wineboot would be better in spite of that I can push up patches though
On Wed Aug 14 11:24:53 2024 +0000, Billy Laws wrote:
If you still think detection in wineboot would be better in spite of that I can push up patches though
With emulation inside ntdll signal handler you wouldn't need additional external interface.
On Wed Aug 14 13:27:29 2024 +0000, Jacek Caban wrote:
With emulation inside ntdll signal handler you wouldn't need additional external interface.
Oh in that sense, i was thinking of SEH. Suppose that works fine then
On Wed Aug 14 19:57:18 2024 +0000, Billy Laws wrote:
Oh in that sense, i was thinking of SEH. Suppose that works fine then
^ turns out windows on arm devices don't expose the big.LITTLE topology or midr in their smbios or GetLogicalProcessorInformationEx and just report a single processor. Is it fine to diverge like this in wine?
On Wed Aug 14 20:44:09 2024 +0000, Billy Laws wrote:
^ turns out windows on arm devices don't expose the big.LITTLE topology or midr in their smbios or GetLogicalProcessorInformationEx and just report a single processor. Is it fine to diverge like this in wine?
Also double checked on an intel CPU with p/e cores, it similarly reports only a single smbios processor