Since the kernel doesn't pass any info on the reason for the fault, disassemble the instruction to detect a store.
Signed-off-by: Richard Henderson <r...@twiddle.net> --- Rather than spam the rest of the reviewed patch series to the list, I'm just sending the update of the one patch that had issues. >From v4, Claudio correctly diagnosed that I had missed the 128-bit stores. Unfortunately, opcode 2 is used for both loads and stores, so one has to use a different mask for them. Previous revisions had a comment about how some of these tests could be merged. Adding another 7 for the 128-bit stores seemed a bridge too far, so I did some easy merging. There are two groups of insns that differ only in pre-/post-/no-increment, or that vary only in fields that don't matter (register input vs immediate input). I no longer try to distinguish those. In the case of C3.3.8-12, there are combinations of bits 10, 11, 21 that are not valid insns. But since we don't really need to be a full disassembler I think that'll be fine for now. With any luck the kernel patch that passes the relevent data down from the trap will be accepted upstream soon, and this will just be legacy. r~ --- user-exec.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/user-exec.c b/user-exec.c index bc58056..8ed6fec 100644 --- a/user-exec.c +++ b/user-exec.c @@ -465,16 +465,29 @@ int cpu_signal_handler(int host_signum, void *pinfo, #elif defined(__aarch64__) -int cpu_signal_handler(int host_signum, void *pinfo, - void *puc) +int cpu_signal_handler(int host_signum, void *pinfo, void *puc) { siginfo_t *info = pinfo; struct ucontext *uc = puc; - uint64_t pc; - int is_write = 0; /* XXX how to determine? */ + uintptr_t pc = uc->uc_mcontext.pc; + uint32_t insn = *(uint32_t *)pc; + bool is_write; - pc = uc->uc_mcontext.pc; - return handle_cpu_signal(pc, (uint64_t)info->si_addr, + /* XXX: need kernel patch to get write flag faster. */ + is_write = ( (insn & 0xbfff0000) == 0x0c000000 /* C3.3.1 */ + || (insn & 0xbfe00000) == 0x0c800000 /* C3.3.2 */ + || (insn & 0xbfdf0000) == 0x0d000000 /* C3.3.3 */ + || (insn & 0xbfc00000) == 0x0d800000 /* C3.3.4 */ + || (insn & 0x3f400000) == 0x08000000 /* C3.3.6 */ + || (insn & 0x3bc00000) == 0x39000000 /* C3.3.13 */ + || (insn & 0x3fc00000) == 0x3d800000 /* ... 128bit */ + /* Ingore bits 10, 11 & 21, controlling indexing. */ + || (insn & 0x3bc00000) == 0x38000000 /* C3.3.8-12 */ + || (insn & 0x3fe00000) == 0x3c800000 /* ... 128bit */ + /* Ignore bits 23 & 24, controlling indexing. */ + || (insn & 0x3a400000) == 0x28000000); /* C3.3.7,14-16 */ + + return handle_cpu_signal(pc, (uintptr_t)info->si_addr, is_write, &uc->uc_sigmask, puc); } -- 1.9.0