linux-user/aarch64: Pass syndrome to EXC_*_ABORT

A proper syndrome is required to fill in the proper si_code.
Use page_get_flags to determine permission vs translation for user-only.

Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20210212184902.1251044-27-richard.henderson@linaro.org
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Richard Henderson 2021-02-12 10:48:57 -08:00 committed by Peter Maydell
parent 1fe2785942
commit 8db94ab4e5
2 changed files with 30 additions and 9 deletions

View File

@ -23,6 +23,7 @@
#include "cpu_loop-common.h" #include "cpu_loop-common.h"
#include "qemu/guest-random.h" #include "qemu/guest-random.h"
#include "hw/semihosting/common-semi.h" #include "hw/semihosting/common-semi.h"
#include "target/arm/syndrome.h"
#define get_user_code_u32(x, gaddr, env) \ #define get_user_code_u32(x, gaddr, env) \
({ abi_long __r = get_user_u32((x), (gaddr)); \ ({ abi_long __r = get_user_u32((x), (gaddr)); \
@ -76,7 +77,7 @@
void cpu_loop(CPUARMState *env) void cpu_loop(CPUARMState *env)
{ {
CPUState *cs = env_cpu(env); CPUState *cs = env_cpu(env);
int trapnr; int trapnr, ec, fsc;
abi_long ret; abi_long ret;
target_siginfo_t info; target_siginfo_t info;
@ -117,9 +118,26 @@ void cpu_loop(CPUARMState *env)
case EXCP_DATA_ABORT: case EXCP_DATA_ABORT:
info.si_signo = TARGET_SIGSEGV; info.si_signo = TARGET_SIGSEGV;
info.si_errno = 0; info.si_errno = 0;
/* XXX: check env->error_code */
info.si_code = TARGET_SEGV_MAPERR;
info._sifields._sigfault._addr = env->exception.vaddress; 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); queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
break; break;
case EXCP_DEBUG: case EXCP_DEBUG:

View File

@ -154,21 +154,24 @@ bool arm_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
bool probe, uintptr_t retaddr) bool probe, uintptr_t retaddr)
{ {
ARMCPU *cpu = ARM_CPU(cs); ARMCPU *cpu = ARM_CPU(cs);
ARMMMUFaultInfo fi = {};
#ifdef CONFIG_USER_ONLY #ifdef CONFIG_USER_ONLY
cpu->env.exception.vaddress = address; int flags = page_get_flags(useronly_clean_ptr(address));
if (access_type == MMU_INST_FETCH) { if (flags & PAGE_VALID) {
cs->exception_index = EXCP_PREFETCH_ABORT; fi.type = ARMFault_Permission;
} else { } 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 #else
hwaddr phys_addr; hwaddr phys_addr;
target_ulong page_size; target_ulong page_size;
int prot, ret; int prot, ret;
MemTxAttrs attrs = {}; MemTxAttrs attrs = {};
ARMMMUFaultInfo fi = {};
ARMCacheAttrs cacheattrs = {}; ARMCacheAttrs cacheattrs = {};
/* /*