Signed-off-by: Richard Henderson <richard.hender...@linaro.org> --- linux-user/aarch64/target_signal.h | 1 + linux-user/aarch64/cpu_loop.c | 34 +++++++++++++++++++++--------- target/arm/mte_helper.c | 10 +++++++++ 3 files changed, 35 insertions(+), 10 deletions(-)
diff --git a/linux-user/aarch64/target_signal.h b/linux-user/aarch64/target_signal.h index 777fb667fe..18013e1b23 100644 --- a/linux-user/aarch64/target_signal.h +++ b/linux-user/aarch64/target_signal.h @@ -21,6 +21,7 @@ typedef struct target_sigaltstack { #include "../generic/signal.h" +#define TARGET_SEGV_MTEAERR 8 /* Asynchronous ARM MTE error */ #define TARGET_SEGV_MTESERR 9 /* Synchronous ARM MTE exception */ #define TARGET_ARCH_HAS_SETUP_FRAME diff --git a/linux-user/aarch64/cpu_loop.c b/linux-user/aarch64/cpu_loop.c index 6867f0db2b..6160a401bd 100644 --- a/linux-user/aarch64/cpu_loop.c +++ b/linux-user/aarch64/cpu_loop.c @@ -72,6 +72,21 @@ put_user_u16(__x, (gaddr)); \ }) +static bool check_mte_async_fault(CPUARMState *env, target_siginfo_t *info) +{ + if (likely(env->cp15.tfsr_el[0] == 0)) { + return false; + } + + env->cp15.tfsr_el[0] = 0; + info->si_signo = TARGET_SIGSEGV; + info->si_errno = 0; + info->_sifields._sigfault._addr = 0; + info->si_code = TARGET_SEGV_MTEAERR; + queue_signal(env, info->si_signo, QEMU_SI_FAULT, info); + return true; +} + /* AArch64 main loop */ void cpu_loop(CPUARMState *env) { @@ -88,15 +103,13 @@ void cpu_loop(CPUARMState *env) switch (trapnr) { case EXCP_SWI: - ret = do_syscall(env, - env->xregs[8], - env->xregs[0], - env->xregs[1], - env->xregs[2], - env->xregs[3], - env->xregs[4], - env->xregs[5], - 0, 0); + if (check_mte_async_fault(env, &info)) { + ret = -TARGET_ERESTARTSYS; + } else { + ret = do_syscall(env, env->xregs[8], env->xregs[0], + env->xregs[1], env->xregs[2], env->xregs[3], + env->xregs[4], env->xregs[5], 0, 0); + } if (ret == -TARGET_ERESTARTSYS) { env->pc -= 4; } else if (ret != -TARGET_QEMU_ESIGRETURN) { @@ -104,7 +117,8 @@ void cpu_loop(CPUARMState *env) } break; case EXCP_INTERRUPT: - /* just indicate that signals should be handled asap */ + /* Just indicate that signals should be handled asap. */ + check_mte_async_fault(env, &info); break; case EXCP_UDEF: info.si_signo = TARGET_SIGILL; diff --git a/target/arm/mte_helper.c b/target/arm/mte_helper.c index 153bd1e9df..d55f8d1e1e 100644 --- a/target/arm/mte_helper.c +++ b/target/arm/mte_helper.c @@ -565,6 +565,16 @@ static void mte_check_fail(CPUARMState *env, uint32_t desc, select = 0; } env->cp15.tfsr_el[el] |= 1 << select; +#ifdef CONFIG_USER_ONLY + /* + * Stand in for a timer irq, setting _TIF_MTE_ASYNC_FAULT, + * which then sends a SIGSEGV when the thread is next scheduled. + * This cpu will return to the main loop at the end of the TB, + * which is rather sooner than "normal". But the alternative + * is waiting until the next syscall. + */ + qemu_cpu_kick(env_cpu(env)); +#endif break; default: -- 2.25.1