diff --git a/linux-user/aarch64/cpu_loop.c b/linux-user/aarch64/cpu_loop.c index b6a2e65593..7c42f65706 100644 --- a/linux-user/aarch64/cpu_loop.c +++ b/linux-user/aarch64/cpu_loop.c @@ -164,6 +164,17 @@ void cpu_loop(CPUARMState *env) EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr); abort(); } + + /* Check for MTE asynchronous faults */ + if (unlikely(env->cp15.tfsr_el[0])) { + 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); + } + process_pending_signals(env); /* Exception return on AArch64 always clears the exclusive monitor, * so any return to running guest code implies this. 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/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: