From 703489071ff72da2f8846d2cb630288cbc37674f Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Fri, 2 Mar 2018 13:32:00 -0500 Subject: [PATCH] armv7m: Replace armv7m.hack with unassigned_access handler For v7m we need to catch attempts to execute from special addresses at 0xfffffff0 and above. Previously we did this with the aid of a hacky special purpose lump of memory in the address space and a check in translate.c for whether we were translating code at those addresses. We can implement this more cleanly using a CPU unassigned access handler which throws the exception if the unassigned access is for one of the special addresses. Backports commit 542b3478a00cb7ef51c259255b3ab1e2a7daada2 from qemu --- qemu/target/arm/cpu.c | 28 ++++++++++++++++++++++++++++ qemu/target/arm/translate.c | 12 ++++++------ 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/qemu/target/arm/cpu.c b/qemu/target/arm/cpu.c index 777bad9c..94db3972 100644 --- a/qemu/target/arm/cpu.c +++ b/qemu/target/arm/cpu.c @@ -291,6 +291,33 @@ bool arm_cpu_exec_interrupt(CPUState *cs, int interrupt_request) } #if !defined(CONFIG_USER_ONLY) || !defined(TARGET_AARCH64) +static void arm_v7m_unassigned_access(CPUState *cpu, hwaddr addr, + bool is_write, bool is_exec, int opaque, + unsigned size) +{ + ARMCPU *arm = ARM_CPU(cpu->uc, cpu); + CPUARMState *env = &arm->env; + + /* ARMv7-M interrupt return works by loading a magic value into the PC. + * On real hardware the load causes the return to occur. The qemu + * implementation performs the jump normally, then does the exception + * return by throwing a special exception when when the CPU tries to + * execute code at the magic address. + */ + if (env->v7m.exception != 0 && addr >= 0xfffffff0 && is_exec) { + cpu->exception_index = EXCP_EXCEPTION_EXIT; + cpu_loop_exit(cpu); + } + + /* In real hardware an attempt to access parts of the address space + * with nothing there will usually cause an external abort. + * However our QEMU board models are often missing device models where + * the guest can boot anyway with the default read-as-zero/writes-ignored + * behaviour that you get without a QEMU unassigned_access hook. + * So just return here to retain that default behaviour. + */ +} + static bool arm_v7m_cpu_exec_interrupt(CPUState *cs, int interrupt_request) { CPUARMState *env = cs->env_ptr; @@ -870,6 +897,7 @@ static void arm_v7m_class_init(struct uc_struct *uc, ObjectClass *oc, void *data cc->do_interrupt = arm_v7m_cpu_do_interrupt; #endif + cc->do_unassigned_access = arm_v7m_unassigned_access; cc->cpu_exec_interrupt = arm_v7m_cpu_exec_interrupt; } diff --git a/qemu/target/arm/translate.c b/qemu/target/arm/translate.c index 567af74b..2655bfee 100644 --- a/qemu/target/arm/translate.c +++ b/qemu/target/arm/translate.c @@ -12053,12 +12053,12 @@ void gen_intermediate_code(CPUARMState *env, TranslationBlock *tb) break; } #else - if (dc->pc >= 0xfffffff0 && arm_dc_feature(dc, ARM_FEATURE_M)) { - /* We always get here via a jump, so know we are not in a - conditional execution block. */ - gen_exception_internal(dc, EXCP_EXCEPTION_EXIT); - dc->is_jmp = DISAS_EXC; - break; + if (arm_dc_feature(dc, ARM_FEATURE_M)) { + /* Branches to the magic exception-return addresses should + * already have been caught via the arm_v7m_unassigned_access hook, + * and never get here. + */ + assert(dc->pc < 0xfffffff0); } #endif