diff --git a/linux-user/aarch64/cpu_loop.c b/linux-user/aarch64/cpu_loop.c index 42b9c15f53..4e43906e66 100644 --- a/linux-user/aarch64/cpu_loop.c +++ b/linux-user/aarch64/cpu_loop.c @@ -23,6 +23,7 @@ #include "cpu_loop-common.h" #include "qemu/guest-random.h" #include "hw/semihosting/common-semi.h" +#include "target/arm/syndrome.h" #define get_user_code_u32(x, gaddr, env) \ ({ abi_long __r = get_user_u32((x), (gaddr)); \ @@ -76,7 +77,7 @@ void cpu_loop(CPUARMState *env) { CPUState *cs = env_cpu(env); - int trapnr; + int trapnr, ec, fsc; abi_long ret; target_siginfo_t info; @@ -117,9 +118,26 @@ void cpu_loop(CPUARMState *env) case EXCP_DATA_ABORT: info.si_signo = TARGET_SIGSEGV; info.si_errno = 0; - /* XXX: check env->error_code */ - info.si_code = TARGET_SEGV_MAPERR; info._sifields._sigfault._addr = env->exception.vaddress; + + /* We should only arrive here with EC in {DATAABORT, INSNABORT}. */ + ec = syn_get_ec(env->exception.syndrome); + assert(ec == EC_DATAABORT || ec == EC_INSNABORT); + + /* Both EC have the same format for FSC, or close enough. */ + fsc = extract32(env->exception.syndrome, 0, 6); + switch (fsc) { + case 0x04 ... 0x07: /* Translation fault, level {0-3} */ + info.si_code = TARGET_SEGV_MAPERR; + break; + case 0x09 ... 0x0b: /* Access flag fault, level {1-3} */ + case 0x0d ... 0x0f: /* Permission fault, level {1-3} */ + info.si_code = TARGET_SEGV_ACCERR; + break; + default: + g_assert_not_reached(); + } + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); break; case EXCP_DEBUG: diff --git a/target/arm/tlb_helper.c b/target/arm/tlb_helper.c index df85079d9f..9609333cbd 100644 --- a/target/arm/tlb_helper.c +++ b/target/arm/tlb_helper.c @@ -154,21 +154,24 @@ bool arm_cpu_tlb_fill(CPUState *cs, vaddr address, int size, bool probe, uintptr_t retaddr) { ARMCPU *cpu = ARM_CPU(cs); + ARMMMUFaultInfo fi = {}; #ifdef CONFIG_USER_ONLY - cpu->env.exception.vaddress = address; - if (access_type == MMU_INST_FETCH) { - cs->exception_index = EXCP_PREFETCH_ABORT; + int flags = page_get_flags(useronly_clean_ptr(address)); + if (flags & PAGE_VALID) { + fi.type = ARMFault_Permission; } else { - cs->exception_index = EXCP_DATA_ABORT; + fi.type = ARMFault_Translation; } - cpu_loop_exit_restore(cs, retaddr); + + /* now we have a real cpu fault */ + cpu_restore_state(cs, retaddr, true); + arm_deliver_fault(cpu, address, access_type, mmu_idx, &fi); #else hwaddr phys_addr; target_ulong page_size; int prot, ret; MemTxAttrs attrs = {}; - ARMMMUFaultInfo fi = {}; ARMCacheAttrs cacheattrs = {}; /*