[Bug 46132] New: Multiple Windows 10 ARM64 apps crash with illegal instruction fault due to access of ARMv8 PMU cycle counter via 'PMCCNTR_EL0' register in EL0 (Linux kernel disallows access by default)

wine-bugs at winehq.org wine-bugs at winehq.org
Mon Nov 12 08:40:47 CST 2018


https://bugs.winehq.org/show_bug.cgi?id=46132

            Bug ID: 46132
           Summary: Multiple Windows 10 ARM64 apps crash with illegal
                    instruction fault due to access of ARMv8 PMU cycle
                    counter via 'PMCCNTR_EL0' register in EL0 (Linux
                    kernel disallows access by default)
           Product: Wine
           Version: 3.20
          Hardware: aarch64
                OS: Linux
            Status: NEW
          Severity: normal
          Priority: P2
         Component: -unknown
          Assignee: wine-bugs at winehq.org
          Reporter: focht at gmx.net
      Distribution: ---

Hello folks,

just for documentation ...

--- snip ---
$ WINEDEBUG=+seh,+loaddll,+process,+relay,+msvcrt wine64 ./gatherosstate.exe 
>>log.txt 2>&1
...
0009:trace:msvcrt:DllMain finished process init
0009:Ret  PE DLL (proc=0x7fae7e3b04,module=0x7fae730000
L"msvcrt.dll",reason=PROCESS_ATTACH,res=0x22fc48) retval=1
0009:Call PE DLL (proc=0x7fae5fd5d8,module=0x7fae580000
L"advapi32.dll",reason=PROCESS_ATTACH,res=0x22fc48)
0009:Ret  PE DLL (proc=0x7fae5fd5d8,module=0x7fae580000
L"advapi32.dll",reason=PROCESS_ATTACH,res=0x22fc48) retval=1
0009:Starting process
L"Z:\\home\\focht\\Downloads\\ARM64-win10-apps\\gatherosstate.exe"
(entryproc=0x14002fd80)
0009:trace:process:NtQueryInformationProcess
(0xffffffffffffffff,0x00000007,0x22f988,0x00000008,(nil))
0009:trace:seh:call_stack_handlers calling handler at 0x7b4d6330 code=c000001d
flags=0
wine: Unhandled illegal instruction at address 0x14002fc0c (thread 0009),
starting debugger...
0009:trace:seh:start_debugger Starting debugger "winedbg --auto 8 32" 
--- snip ---

strace:

--- snip ---
2752  [000000014002fc0c] --- SIGILL {si_signo=SIGILL, si_code=ILL_ILLOPC,
si_addr=0x14002fc0c} --- 
--- snip ---

Disassembly around faulting instruction:

--- snip ---
start:
000000014002FD80 F3 53 BE A9  STP      X19, X20, [SP,#-0x20+var_s0]!
000000014002FD84 F5 0B 00 F9  STR      X21, [SP,#var_s10]
000000014002FD88 FD 7B BF A9  STP      X29, X30, [SP,#var_10]!
000000014002FD8C FD 03 00 91  MOV      X29, SP
000000014002FD90 13 00 80 52  MOV      W19, #0
000000014002FD94 9B FF FF 97  BL       sub_14002FC00
000000014002FD98 F5 03 00 2A  MOV      W21, W0
...
sub_14002FC00:
000000014002FC00 F3 0F 1F F8  STR      X19, [SP,#-0x10+var_s0]!
000000014002FC04 FD 7B BF A9  STP      X29, X30, [SP,#var_10]!
000000014002FC08 FD 03 00 91  MOV      X29, SP
000000014002FC0C 08 9D 3B D5  MRS      X8, #3, c9, c13, #0         ; *boom*
000000014002FC10 0A 03 00 B0  ADRP     X10, #qword_140090670 at PAGE
000000014002FC14 53 C1 19 91  ADD      X19, X10, #qword_140090670 at PAGEOFF
000000014002FC18 08 79 40 92  AND      X8, X8, #0x7FFFFFFF
--- snip ---

Decoding the sysreg using ARM's ARMv8 Processor Technical Reference Manual:

MRS <Xt>, (<systemreg>|S<op0>_<op1>_<Cn>_<Cm>_<op2>)

08 9D 3B D5 -> D5 3B 9D 08

|   D5   |   3B      |     9D  |    08   |
|11010101|00 1 11 011|1001 1101|000 01000|
|  OPCode   |L|o0|op1|CRn |CRm |op2| Rt  |

op0 = 3
op1 = 3
op2 = 0
CRn = 9
CRm = 13
Rt  = 8

0x08,0x9d,0x3b,0xd5 = 'MRS X8, PMCCNTR_EL0'

Microsoft docs:

https://docs.microsoft.com/en-us/cpp/build/arm64-windows-abi-conventions?view=vs-2017

--- quote ---
Cycle counter

All ARMv8 CPUs are required to support a cycle counter register. This is a
64-bit register that Windows configures
to be readable at any exception level (including user mode). It can be accessed
via the special PMCCNTR_EL0 
register, using the MSR opcode in assembly code, or the _ReadStatusReg
intrinsic in C/C++ code.

Note that the cycle counter here is a true cycle counter, not a wall clock, and
thus the counting frequency
will vary with the processor frequency. If you feel you must know the frequency
of the cycle counter,
you should not be using the cycle counter. Instead, you want to measure wall
clock time, for which you
should use QueryPerformanceCounter.
--- quote ---

Defined as 'ReadTimeStampCounter()' in Windows 10 SDK header 'winnt.h'.

Current QEMU for ARM64 supports it (if not run under real hardware):

https://github.com/qemu/qemu/blob/master/target/arm/helper.c#L1410

--- snip ---
#ifndef CONFIG_USER_ONLY
...
    { .name = "PMCCNTR_EL0", .state = ARM_CP_STATE_AA64,
      .opc0 = 3, .opc1 = 3, .crn = 9, .crm = 13, .opc2 = 0,
      .access = PL0_RW, .accessfn = pmreg_access_ccntr,
      .type = ARM_CP_IO,
      .readfn = pmccntr_read, .writefn = pmccntr_write, },
#endif
--- snip ---

The relevant piece of Linux kernel code:

https://github.com/torvalds/linux/commit/60792ad349f3c6dc5735aafefe5dc9121c79e320

--- quote ---
arm64: kernel: enforce pmuserenr_el0 initialization and restore

The pmuserenr_el0 register value is architecturally UNKNOWN on reset.
Current kernel code resets that register value iff the core pmu device is
correctly probed in the kernel. On platforms with missing DT pmu nodes (or
disabled perf events in the kernel), the pmu is not probed, therefore the
pmuserenr_el0 register is not reset in the kernel, which means that its
value retains the reset value that is architecturally UNKNOWN (system
may run with eg pmuserenr_el0 == 0x1, which means that PMU counters access
is available at EL0, which must be disallowed).

This patch adds code that resets pmuserenr_el0 on cold boot and restores
it on core resume from shutdown, so that the pmuserenr_el0 setup is
always enforced in the kernel.
--- quote ---

Since the Linux kernel maintainers disallow PMU counter access in EL0 by
default, one has to patch the Linux kernel or use a helper kernel module.
Windows 10 ARM64 likely has PMU counter access in EL0 enabled by default.

There were some attempts in the past, but they never made it in.

https://patchwork.kernel.org/patch/5217341/

https://github.com/zhiyisun/enable_arm_pmu/tree/dev

Anyway, nothing to fix in Wine here. Upstream (if at all).

Regards

-- 
Do not reply to this email, post in Bugzilla using the
above URL to reply.
You are receiving this mail because:
You are watching all bug changes.



More information about the wine-bugs mailing list