All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Alex Bennée" <alex.bennee@linaro.org>
To: qemu-devel@nongnu.org
Cc: "Peter Maydell" <peter.maydell@linaro.org>,
	qemu-arm@nongnu.org, "Philippe Mathieu-Daudé" <philmd@redhat.com>,
	"Samuel Ortiz" <sameo@linux.intel.com>
Subject: Re: [Qemu-devel] [PATCH v2 08/23] target/arm: Move all v7m insn helpers into their own file
Date: Mon, 17 Jun 2019 12:42:50 +0100	[thread overview]
Message-ID: <8736k8bfph.fsf@zen.linaroharston> (raw)
In-Reply-To: <20190615154352.26824-9-philmd@redhat.com>


Philippe Mathieu-Daudé <philmd@redhat.com> writes:

> From: Samuel Ortiz <sameo@linux.intel.com>
>
> In preparation for supporting TCG disablement on ARM, we move most
> of TCG related v7m helpers and APIs into their own file.
>
> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
> [PMD: Patch rewritten]
> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
> ---
> Is there a way to not use $CONFIG_USER_ONLY?

Is this because the CONFIG_ARM_V7M symbol only appears for softmmu
targets but we still want vXm -cpu's for user mode?

>
>  target/arm/Makefile.objs |   1 +
>  target/arm/helper.c      | 633 -------------------------------------
>  target/arm/v7m_helper.c  | 654 +++++++++++++++++++++++++++++++++++++++
>  3 files changed, 655 insertions(+), 633 deletions(-)
>  create mode 100644 target/arm/v7m_helper.c
>
> diff --git a/target/arm/Makefile.objs b/target/arm/Makefile.objs
> index 72b42f825f..5f3f965cc6 100644
> --- a/target/arm/Makefile.objs
> +++ b/target/arm/Makefile.objs
> @@ -35,6 +35,7 @@ obj-y += translate.o op_helper.o
>  obj-y += crypto_helper.o
>  obj-y += iwmmxt_helper.o vec_helper.o
>  obj-y += neon_helper.o vfp_helper.o
> +obj-$(call lor,$(CONFIG_USER_ONLY),$(CONFIG_ARM_V7M)) += v7m_helper.o
>
>  obj-$(TARGET_AARCH64) += translate-a64.o helper-a64.o
>  obj-$(TARGET_AARCH64) += translate-sve.o sve_helper.o
> diff --git a/target/arm/helper.c b/target/arm/helper.c
> index a1e74cc471..a829086c6d 100644
> --- a/target/arm/helper.c
> +++ b/target/arm/helper.c
> @@ -20,7 +20,6 @@
>  #include "qemu/crc32c.h"
>  #include "qemu/qemu-print.h"
>  #include "exec/exec-all.h"
> -#include "exec/cpu_ldst.h"
>  #include "arm_ldst.h"
>  #include <zlib.h> /* For crc32 */
>  #include "hw/semihosting/semihost.h"
> @@ -7456,75 +7455,6 @@ uint32_t HELPER(rbit)(uint32_t x)
>
>  #ifdef CONFIG_USER_ONLY
>
> -/* These should probably raise undefined insn exceptions.  */
> -void HELPER(v7m_msr)(CPUARMState *env, uint32_t reg, uint32_t val)
> -{
> -    ARMCPU *cpu = env_archcpu(env);
> -
> -    cpu_abort(CPU(cpu), "v7m_msr %d\n", reg);
> -}
> -
> -uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
> -{
> -    ARMCPU *cpu = env_archcpu(env);
> -
> -    cpu_abort(CPU(cpu), "v7m_mrs %d\n", reg);
> -    return 0;
> -}
> -
> -void HELPER(v7m_bxns)(CPUARMState *env, uint32_t dest)
> -{
> -    /* translate.c should never generate calls here in user-only mode */
> -    g_assert_not_reached();
> -}
> -
> -void HELPER(v7m_blxns)(CPUARMState *env, uint32_t dest)
> -{
> -    /* translate.c should never generate calls here in user-only mode */
> -    g_assert_not_reached();
> -}
> -
> -void HELPER(v7m_preserve_fp_state)(CPUARMState *env)
> -{
> -    /* translate.c should never generate calls here in user-only mode */
> -    g_assert_not_reached();
> -}
> -
> -void HELPER(v7m_vlstm)(CPUARMState *env, uint32_t fptr)
> -{
> -    /* translate.c should never generate calls here in user-only mode */
> -    g_assert_not_reached();
> -}
> -
> -void HELPER(v7m_vlldm)(CPUARMState *env, uint32_t fptr)
> -{
> -    /* translate.c should never generate calls here in user-only mode */
> -    g_assert_not_reached();
> -}
> -
> -uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t addr, uint32_t op)
> -{
> -    /*
> -     * The TT instructions can be used by unprivileged code, but in
> -     * user-only emulation we don't have the MPU.
> -     * Luckily since we know we are NonSecure unprivileged (and that in
> -     * turn means that the A flag wasn't specified), all the bits in the
> -     * register must be zero:
> -     *  IREGION: 0 because IRVALID is 0
> -     *  IRVALID: 0 because NS
> -     *  S: 0 because NS
> -     *  NSRW: 0 because NS
> -     *  NSR: 0 because NS
> -     *  RW: 0 because unpriv and A flag not set
> -     *  R: 0 because unpriv and A flag not set
> -     *  SRVALID: 0 because NS
> -     *  MRVALID: 0 because unpriv and A flag not set
> -     *  SREGION: 0 becaus SRVALID is 0
> -     *  MREGION: 0 because MRVALID is 0
> -     */
> -    return 0;
> -}
> -
>  void switch_mode(CPUARMState *env, int mode)
>  {
>      ARMCPU *cpu = env_archcpu(env);
> @@ -8048,109 +7978,6 @@ void switch_v7m_security_state(CPUARMState *env, bool new_secstate)
>      }
>  }
>
> -void HELPER(v7m_bxns)(CPUARMState *env, uint32_t dest)
> -{
> -    /*
> -     * Handle v7M BXNS:
> -     *  - if the return value is a magic value, do exception return (like BX)
> -     *  - otherwise bit 0 of the return value is the target security state
> -     */
> -    uint32_t min_magic;
> -
> -    if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
> -        /* Covers FNC_RETURN and EXC_RETURN magic */
> -        min_magic = FNC_RETURN_MIN_MAGIC;
> -    } else {
> -        /* EXC_RETURN magic only */
> -        min_magic = EXC_RETURN_MIN_MAGIC;
> -    }
> -
> -    if (dest >= min_magic) {
> -        /*
> -         * This is an exception return magic value; put it where
> -         * do_v7m_exception_exit() expects and raise EXCEPTION_EXIT.
> -         * Note that if we ever add gen_ss_advance() singlestep support to
> -         * M profile this should count as an "instruction execution complete"
> -         * event (compare gen_bx_excret_final_code()).
> -         */
> -        env->regs[15] = dest & ~1;
> -        env->thumb = dest & 1;
> -        HELPER(exception_internal)(env, EXCP_EXCEPTION_EXIT);
> -        /* notreached */
> -    }
> -
> -    /* translate.c should have made BXNS UNDEF unless we're secure */
> -    assert(env->v7m.secure);
> -
> -    if (!(dest & 1)) {
> -        env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_SFPA_MASK;
> -    }
> -    switch_v7m_security_state(env, dest & 1);
> -    env->thumb = 1;
> -    env->regs[15] = dest & ~1;
> -}
> -
> -void HELPER(v7m_blxns)(CPUARMState *env, uint32_t dest)
> -{
> -    /*
> -     * Handle v7M BLXNS:
> -     *  - bit 0 of the destination address is the target security state
> -     */
> -
> -    /* At this point regs[15] is the address just after the BLXNS */
> -    uint32_t nextinst = env->regs[15] | 1;
> -    uint32_t sp = env->regs[13] - 8;
> -    uint32_t saved_psr;
> -
> -    /* translate.c will have made BLXNS UNDEF unless we're secure */
> -    assert(env->v7m.secure);
> -
> -    if (dest & 1) {
> -        /*
> -         * Target is Secure, so this is just a normal BLX,
> -         * except that the low bit doesn't indicate Thumb/not.
> -         */
> -        env->regs[14] = nextinst;
> -        env->thumb = 1;
> -        env->regs[15] = dest & ~1;
> -        return;
> -    }
> -
> -    /* Target is non-secure: first push a stack frame */
> -    if (!QEMU_IS_ALIGNED(sp, 8)) {
> -        qemu_log_mask(LOG_GUEST_ERROR,
> -                      "BLXNS with misaligned SP is UNPREDICTABLE\n");
> -    }
> -
> -    if (sp < v7m_sp_limit(env)) {
> -        raise_exception(env, EXCP_STKOF, 0, 1);
> -    }
> -
> -    saved_psr = env->v7m.exception;
> -    if (env->v7m.control[M_REG_S] & R_V7M_CONTROL_SFPA_MASK) {
> -        saved_psr |= XPSR_SFPA;
> -    }
> -
> -    /* Note that these stores can throw exceptions on MPU faults */
> -    cpu_stl_data(env, sp, nextinst);
> -    cpu_stl_data(env, sp + 4, saved_psr);
> -
> -    env->regs[13] = sp;
> -    env->regs[14] = 0xfeffffff;
> -    if (arm_v7m_is_handler_mode(env)) {
> -        /*
> -         * Write a dummy value to IPSR, to avoid leaking the current secure
> -         * exception number to non-secure code. This is guaranteed not
> -         * to cause write_v7m_exception() to actually change stacks.
> -         */
> -        write_v7m_exception(env, 1);
> -    }
> -    env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_SFPA_MASK;
> -    switch_v7m_security_state(env, 0);
> -    env->thumb = 1;
> -    env->regs[15] = dest;
> -}
> -
>  static uint32_t *get_v7m_sp_ptr(CPUARMState *env, bool secure, bool threadmode,
>                                  bool spsel)
>  {
> @@ -12760,466 +12587,6 @@ hwaddr arm_cpu_get_phys_page_attrs_debug(CPUState *cs, vaddr addr,
>      return phys_addr;
>  }
>
> -uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
> -{
> -    uint32_t mask;
> -    unsigned el = arm_current_el(env);
> -
> -    /* First handle registers which unprivileged can read */
> -
> -    switch (reg) {
> -    case 0 ... 7: /* xPSR sub-fields */
> -        mask = 0;
> -        if ((reg & 1) && el) {
> -            mask |= XPSR_EXCP; /* IPSR (unpriv. reads as zero) */
> -        }
> -        if (!(reg & 4)) {
> -            mask |= XPSR_NZCV | XPSR_Q; /* APSR */
> -            if (arm_feature(env, ARM_FEATURE_THUMB_DSP)) {
> -                mask |= XPSR_GE;
> -            }
> -        }
> -        /* EPSR reads as zero */
> -        return xpsr_read(env) & mask;
> -        break;
> -    case 20: /* CONTROL */
> -    {
> -        uint32_t value = env->v7m.control[env->v7m.secure];
> -        if (!env->v7m.secure) {
> -            /* SFPA is RAZ/WI from NS; FPCA is stored in the M_REG_S bank */
> -            value |= env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK;
> -        }
> -        return value;
> -    }
> -    case 0x94: /* CONTROL_NS */
> -        /*
> -         * We have to handle this here because unprivileged Secure code
> -         * can read the NS CONTROL register.
> -         */
> -        if (!env->v7m.secure) {
> -            return 0;
> -        }
> -        return env->v7m.control[M_REG_NS] |
> -            (env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK);
> -    }
> -
> -    if (el == 0) {
> -        return 0; /* unprivileged reads others as zero */
> -    }
> -
> -    if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
> -        switch (reg) {
> -        case 0x88: /* MSP_NS */
> -            if (!env->v7m.secure) {
> -                return 0;
> -            }
> -            return env->v7m.other_ss_msp;
> -        case 0x89: /* PSP_NS */
> -            if (!env->v7m.secure) {
> -                return 0;
> -            }
> -            return env->v7m.other_ss_psp;
> -        case 0x8a: /* MSPLIM_NS */
> -            if (!env->v7m.secure) {
> -                return 0;
> -            }
> -            return env->v7m.msplim[M_REG_NS];
> -        case 0x8b: /* PSPLIM_NS */
> -            if (!env->v7m.secure) {
> -                return 0;
> -            }
> -            return env->v7m.psplim[M_REG_NS];
> -        case 0x90: /* PRIMASK_NS */
> -            if (!env->v7m.secure) {
> -                return 0;
> -            }
> -            return env->v7m.primask[M_REG_NS];
> -        case 0x91: /* BASEPRI_NS */
> -            if (!env->v7m.secure) {
> -                return 0;
> -            }
> -            return env->v7m.basepri[M_REG_NS];
> -        case 0x93: /* FAULTMASK_NS */
> -            if (!env->v7m.secure) {
> -                return 0;
> -            }
> -            return env->v7m.faultmask[M_REG_NS];
> -        case 0x98: /* SP_NS */
> -        {
> -            /*
> -             * This gives the non-secure SP selected based on whether we're
> -             * currently in handler mode or not, using the NS CONTROL.SPSEL.
> -             */
> -            bool spsel = env->v7m.control[M_REG_NS] & R_V7M_CONTROL_SPSEL_MASK;
> -
> -            if (!env->v7m.secure) {
> -                return 0;
> -            }
> -            if (!arm_v7m_is_handler_mode(env) && spsel) {
> -                return env->v7m.other_ss_psp;
> -            } else {
> -                return env->v7m.other_ss_msp;
> -            }
> -        }
> -        default:
> -            break;
> -        }
> -    }
> -
> -    switch (reg) {
> -    case 8: /* MSP */
> -        return v7m_using_psp(env) ? env->v7m.other_sp : env->regs[13];
> -    case 9: /* PSP */
> -        return v7m_using_psp(env) ? env->regs[13] : env->v7m.other_sp;
> -    case 10: /* MSPLIM */
> -        if (!arm_feature(env, ARM_FEATURE_V8)) {
> -            goto bad_reg;
> -        }
> -        return env->v7m.msplim[env->v7m.secure];
> -    case 11: /* PSPLIM */
> -        if (!arm_feature(env, ARM_FEATURE_V8)) {
> -            goto bad_reg;
> -        }
> -        return env->v7m.psplim[env->v7m.secure];
> -    case 16: /* PRIMASK */
> -        return env->v7m.primask[env->v7m.secure];
> -    case 17: /* BASEPRI */
> -    case 18: /* BASEPRI_MAX */
> -        return env->v7m.basepri[env->v7m.secure];
> -    case 19: /* FAULTMASK */
> -        return env->v7m.faultmask[env->v7m.secure];
> -    default:
> -    bad_reg:
> -        qemu_log_mask(LOG_GUEST_ERROR, "Attempt to read unknown special"
> -                                       " register %d\n", reg);
> -        return 0;
> -    }
> -}
> -
> -void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val)
> -{
> -    /*
> -     * We're passed bits [11..0] of the instruction; extract
> -     * SYSm and the mask bits.
> -     * Invalid combinations of SYSm and mask are UNPREDICTABLE;
> -     * we choose to treat them as if the mask bits were valid.
> -     * NB that the pseudocode 'mask' variable is bits [11..10],
> -     * whereas ours is [11..8].
> -     */
> -    uint32_t mask = extract32(maskreg, 8, 4);
> -    uint32_t reg = extract32(maskreg, 0, 8);
> -    int cur_el = arm_current_el(env);
> -
> -    if (cur_el == 0 && reg > 7 && reg != 20) {
> -        /*
> -         * only xPSR sub-fields and CONTROL.SFPA may be written by
> -         * unprivileged code
> -         */
> -        return;
> -    }
> -
> -    if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
> -        switch (reg) {
> -        case 0x88: /* MSP_NS */
> -            if (!env->v7m.secure) {
> -                return;
> -            }
> -            env->v7m.other_ss_msp = val;
> -            return;
> -        case 0x89: /* PSP_NS */
> -            if (!env->v7m.secure) {
> -                return;
> -            }
> -            env->v7m.other_ss_psp = val;
> -            return;
> -        case 0x8a: /* MSPLIM_NS */
> -            if (!env->v7m.secure) {
> -                return;
> -            }
> -            env->v7m.msplim[M_REG_NS] = val & ~7;
> -            return;
> -        case 0x8b: /* PSPLIM_NS */
> -            if (!env->v7m.secure) {
> -                return;
> -            }
> -            env->v7m.psplim[M_REG_NS] = val & ~7;
> -            return;
> -        case 0x90: /* PRIMASK_NS */
> -            if (!env->v7m.secure) {
> -                return;
> -            }
> -            env->v7m.primask[M_REG_NS] = val & 1;
> -            return;
> -        case 0x91: /* BASEPRI_NS */
> -            if (!env->v7m.secure || !arm_feature(env, ARM_FEATURE_M_MAIN)) {
> -                return;
> -            }
> -            env->v7m.basepri[M_REG_NS] = val & 0xff;
> -            return;
> -        case 0x93: /* FAULTMASK_NS */
> -            if (!env->v7m.secure || !arm_feature(env, ARM_FEATURE_M_MAIN)) {
> -                return;
> -            }
> -            env->v7m.faultmask[M_REG_NS] = val & 1;
> -            return;
> -        case 0x94: /* CONTROL_NS */
> -            if (!env->v7m.secure) {
> -                return;
> -            }
> -            write_v7m_control_spsel_for_secstate(env,
> -                                                 val & R_V7M_CONTROL_SPSEL_MASK,
> -                                                 M_REG_NS);
> -            if (arm_feature(env, ARM_FEATURE_M_MAIN)) {
> -                env->v7m.control[M_REG_NS] &= ~R_V7M_CONTROL_NPRIV_MASK;
> -                env->v7m.control[M_REG_NS] |= val & R_V7M_CONTROL_NPRIV_MASK;
> -            }
> -            /*
> -             * SFPA is RAZ/WI from NS. FPCA is RO if NSACR.CP10 == 0,
> -             * RES0 if the FPU is not present, and is stored in the S bank
> -             */
> -            if (arm_feature(env, ARM_FEATURE_VFP) &&
> -                extract32(env->v7m.nsacr, 10, 1)) {
> -                env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_FPCA_MASK;
> -                env->v7m.control[M_REG_S] |= val & R_V7M_CONTROL_FPCA_MASK;
> -            }
> -            return;
> -        case 0x98: /* SP_NS */
> -        {
> -            /*
> -             * This gives the non-secure SP selected based on whether we're
> -             * currently in handler mode or not, using the NS CONTROL.SPSEL.
> -             */
> -            bool spsel = env->v7m.control[M_REG_NS] & R_V7M_CONTROL_SPSEL_MASK;
> -            bool is_psp = !arm_v7m_is_handler_mode(env) && spsel;
> -            uint32_t limit;
> -
> -            if (!env->v7m.secure) {
> -                return;
> -            }
> -
> -            limit = is_psp ? env->v7m.psplim[false] : env->v7m.msplim[false];
> -
> -            if (val < limit) {
> -                CPUState *cs = env_cpu(env);
> -
> -                cpu_restore_state(cs, GETPC(), true);
> -                raise_exception(env, EXCP_STKOF, 0, 1);
> -            }
> -
> -            if (is_psp) {
> -                env->v7m.other_ss_psp = val;
> -            } else {
> -                env->v7m.other_ss_msp = val;
> -            }
> -            return;
> -        }
> -        default:
> -            break;
> -        }
> -    }
> -
> -    switch (reg) {
> -    case 0 ... 7: /* xPSR sub-fields */
> -        /* only APSR is actually writable */
> -        if (!(reg & 4)) {
> -            uint32_t apsrmask = 0;
> -
> -            if (mask & 8) {
> -                apsrmask |= XPSR_NZCV | XPSR_Q;
> -            }
> -            if ((mask & 4) && arm_feature(env, ARM_FEATURE_THUMB_DSP)) {
> -                apsrmask |= XPSR_GE;
> -            }
> -            xpsr_write(env, val, apsrmask);
> -        }
> -        break;
> -    case 8: /* MSP */
> -        if (v7m_using_psp(env)) {
> -            env->v7m.other_sp = val;
> -        } else {
> -            env->regs[13] = val;
> -        }
> -        break;
> -    case 9: /* PSP */
> -        if (v7m_using_psp(env)) {
> -            env->regs[13] = val;
> -        } else {
> -            env->v7m.other_sp = val;
> -        }
> -        break;
> -    case 10: /* MSPLIM */
> -        if (!arm_feature(env, ARM_FEATURE_V8)) {
> -            goto bad_reg;
> -        }
> -        env->v7m.msplim[env->v7m.secure] = val & ~7;
> -        break;
> -    case 11: /* PSPLIM */
> -        if (!arm_feature(env, ARM_FEATURE_V8)) {
> -            goto bad_reg;
> -        }
> -        env->v7m.psplim[env->v7m.secure] = val & ~7;
> -        break;
> -    case 16: /* PRIMASK */
> -        env->v7m.primask[env->v7m.secure] = val & 1;
> -        break;
> -    case 17: /* BASEPRI */
> -        if (!arm_feature(env, ARM_FEATURE_M_MAIN)) {
> -            goto bad_reg;
> -        }
> -        env->v7m.basepri[env->v7m.secure] = val & 0xff;
> -        break;
> -    case 18: /* BASEPRI_MAX */
> -        if (!arm_feature(env, ARM_FEATURE_M_MAIN)) {
> -            goto bad_reg;
> -        }
> -        val &= 0xff;
> -        if (val != 0 && (val < env->v7m.basepri[env->v7m.secure]
> -                         || env->v7m.basepri[env->v7m.secure] == 0)) {
> -            env->v7m.basepri[env->v7m.secure] = val;
> -        }
> -        break;
> -    case 19: /* FAULTMASK */
> -        if (!arm_feature(env, ARM_FEATURE_M_MAIN)) {
> -            goto bad_reg;
> -        }
> -        env->v7m.faultmask[env->v7m.secure] = val & 1;
> -        break;
> -    case 20: /* CONTROL */
> -        /*
> -         * Writing to the SPSEL bit only has an effect if we are in
> -         * thread mode; other bits can be updated by any privileged code.
> -         * write_v7m_control_spsel() deals with updating the SPSEL bit in
> -         * env->v7m.control, so we only need update the others.
> -         * For v7M, we must just ignore explicit writes to SPSEL in handler
> -         * mode; for v8M the write is permitted but will have no effect.
> -         * All these bits are writes-ignored from non-privileged code,
> -         * except for SFPA.
> -         */
> -        if (cur_el > 0 && (arm_feature(env, ARM_FEATURE_V8) ||
> -                           !arm_v7m_is_handler_mode(env))) {
> -            write_v7m_control_spsel(env, (val & R_V7M_CONTROL_SPSEL_MASK) != 0);
> -        }
> -        if (cur_el > 0 && arm_feature(env, ARM_FEATURE_M_MAIN)) {
> -            env->v7m.control[env->v7m.secure] &= ~R_V7M_CONTROL_NPRIV_MASK;
> -            env->v7m.control[env->v7m.secure] |= val & R_V7M_CONTROL_NPRIV_MASK;
> -        }
> -        if (arm_feature(env, ARM_FEATURE_VFP)) {
> -            /*
> -             * SFPA is RAZ/WI from NS or if no FPU.
> -             * FPCA is RO if NSACR.CP10 == 0, RES0 if the FPU is not present.
> -             * Both are stored in the S bank.
> -             */
> -            if (env->v7m.secure) {
> -                env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_SFPA_MASK;
> -                env->v7m.control[M_REG_S] |= val & R_V7M_CONTROL_SFPA_MASK;
> -            }
> -            if (cur_el > 0 &&
> -                (env->v7m.secure || !arm_feature(env, ARM_FEATURE_M_SECURITY) ||
> -                 extract32(env->v7m.nsacr, 10, 1))) {
> -                env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_FPCA_MASK;
> -                env->v7m.control[M_REG_S] |= val & R_V7M_CONTROL_FPCA_MASK;
> -            }
> -        }
> -        break;
> -    default:
> -    bad_reg:
> -        qemu_log_mask(LOG_GUEST_ERROR, "Attempt to write unknown special"
> -                                       " register %d\n", reg);
> -        return;
> -    }
> -}
> -
> -uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t addr, uint32_t op)
> -{
> -    /* Implement the TT instruction. op is bits [7:6] of the insn. */
> -    bool forceunpriv = op & 1;
> -    bool alt = op & 2;
> -    V8M_SAttributes sattrs = {};
> -    uint32_t tt_resp;
> -    bool r, rw, nsr, nsrw, mrvalid;
> -    int prot;
> -    ARMMMUFaultInfo fi = {};
> -    MemTxAttrs attrs = {};
> -    hwaddr phys_addr;
> -    ARMMMUIdx mmu_idx;
> -    uint32_t mregion;
> -    bool targetpriv;
> -    bool targetsec = env->v7m.secure;
> -    bool is_subpage;
> -
> -    /*
> -     * Work out what the security state and privilege level we're
> -     * interested in is...
> -     */
> -    if (alt) {
> -        targetsec = !targetsec;
> -    }
> -
> -    if (forceunpriv) {
> -        targetpriv = false;
> -    } else {
> -        targetpriv = arm_v7m_is_handler_mode(env) ||
> -            !(env->v7m.control[targetsec] & R_V7M_CONTROL_NPRIV_MASK);
> -    }
> -
> -    /* ...and then figure out which MMU index this is */
> -    mmu_idx = arm_v7m_mmu_idx_for_secstate_and_priv(env, targetsec, targetpriv);
> -
> -    /*
> -     * We know that the MPU and SAU don't care about the access type
> -     * for our purposes beyond that we don't want to claim to be
> -     * an insn fetch, so we arbitrarily call this a read.
> -     */
> -
> -    /*
> -     * MPU region info only available for privileged or if
> -     * inspecting the other MPU state.
> -     */
> -    if (arm_current_el(env) != 0 || alt) {
> -        /* We can ignore the return value as prot is always set */
> -        pmsav8_mpu_lookup(env, addr, MMU_DATA_LOAD, mmu_idx,
> -                          &phys_addr, &attrs, &prot, &is_subpage,
> -                          &fi, &mregion);
> -        if (mregion == -1) {
> -            mrvalid = false;
> -            mregion = 0;
> -        } else {
> -            mrvalid = true;
> -        }
> -        r = prot & PAGE_READ;
> -        rw = prot & PAGE_WRITE;
> -    } else {
> -        r = false;
> -        rw = false;
> -        mrvalid = false;
> -        mregion = 0;
> -    }
> -
> -    if (env->v7m.secure) {
> -        v8m_security_lookup(env, addr, MMU_DATA_LOAD, mmu_idx, &sattrs);
> -        nsr = sattrs.ns && r;
> -        nsrw = sattrs.ns && rw;
> -    } else {
> -        sattrs.ns = true;
> -        nsr = false;
> -        nsrw = false;
> -    }
> -
> -    tt_resp = (sattrs.iregion << 24) |
> -        (sattrs.irvalid << 23) |
> -        ((!sattrs.ns) << 22) |
> -        (nsrw << 21) |
> -        (nsr << 20) |
> -        (rw << 19) |
> -        (r << 18) |
> -        (sattrs.srvalid << 17) |
> -        (mrvalid << 16) |
> -        (sattrs.sregion << 8) |
> -        mregion;
> -
> -    return tt_resp;
> -}
> -
>  #endif
>
>  bool arm_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
> diff --git a/target/arm/v7m_helper.c b/target/arm/v7m_helper.c
> new file mode 100644
> index 0000000000..321154966e
> --- /dev/null
> +++ b/target/arm/v7m_helper.c
> @@ -0,0 +1,654 @@
> +/*
> + * ARM v7-M helpers.
> + *
> + * This code is licensed under the GNU GPL v2 or later.
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +#include "qemu/osdep.h"
> +#include "sysemu/sysemu.h"
> +#include "cpu.h"
> +#include "internals.h"
> +#include "exec/helper-proto.h"
> +#include "exec/exec-all.h"
> +#include "arm_ldst.h"
> +#include "hw/semihosting/semihost.h"
> +#include "fpu/softfloat.h"
> +
> +#if defined(CONFIG_USER_ONLY)
> +
> +/* These should probably raise undefined insn exceptions.  */
> +void HELPER(v7m_msr)(CPUARMState *env, uint32_t reg, uint32_t val)
> +{
> +    ARMCPU *cpu = env_archcpu(env);
> +
> +    cpu_abort(CPU(cpu), "v7m_msr %d\n", reg);
> +}
> +
> +uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
> +{
> +    ARMCPU *cpu = env_archcpu(env);
> +
> +    cpu_abort(CPU(cpu), "v7m_mrs %d\n", reg);
> +    return 0;
> +}
> +
> +void HELPER(v7m_bxns)(CPUARMState *env, uint32_t dest)
> +{
> +    /* translate.c should never generate calls here in user-only mode */
> +    g_assert_not_reached();
> +}
> +
> +void HELPER(v7m_blxns)(CPUARMState *env, uint32_t dest)
> +{
> +    /* translate.c should never generate calls here in user-only mode */
> +    g_assert_not_reached();
> +}
> +
> +void HELPER(v7m_preserve_fp_state)(CPUARMState *env)
> +{
> +    /* translate.c should never generate calls here in user-only mode */
> +    g_assert_not_reached();
> +}
> +
> +void HELPER(v7m_vlstm)(CPUARMState *env, uint32_t fptr)
> +{
> +    /* translate.c should never generate calls here in user-only mode */
> +    g_assert_not_reached();
> +}
> +
> +void HELPER(v7m_vlldm)(CPUARMState *env, uint32_t fptr)
> +{
> +    /* translate.c should never generate calls here in user-only mode */
> +    g_assert_not_reached();
> +}
> +
> +uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t addr, uint32_t op)
> +{
> +    /*
> +     * The TT instructions can be used by unprivileged code, but in
> +     * user-only emulation we don't have the MPU.
> +     * Luckily since we know we are NonSecure unprivileged (and that in
> +     * turn means that the A flag wasn't specified), all the bits in the
> +     * register must be zero:
> +     *  IREGION: 0 because IRVALID is 0
> +     *  IRVALID: 0 because NS
> +     *  S: 0 because NS
> +     *  NSRW: 0 because NS
> +     *  NSR: 0 because NS
> +     *  RW: 0 because unpriv and A flag not set
> +     *  R: 0 because unpriv and A flag not set
> +     *  SRVALID: 0 because NS
> +     *  MRVALID: 0 because unpriv and A flag not set
> +     *  SREGION: 0 becaus SRVALID is 0
> +     *  MREGION: 0 because MRVALID is 0
> +     */
> +    return 0;
> +}
> +
> +#else
> +
> +void HELPER(v7m_bxns)(CPUARMState *env, uint32_t dest)
> +{
> +    /*
> +     * Handle v7M BXNS:
> +     *  - if the return value is a magic value, do exception return (like BX)
> +     *  - otherwise bit 0 of the return value is the target security state
> +     */
> +    uint32_t min_magic;
> +
> +    if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
> +        /* Covers FNC_RETURN and EXC_RETURN magic */
> +        min_magic = FNC_RETURN_MIN_MAGIC;
> +    } else {
> +        /* EXC_RETURN magic only */
> +        min_magic = EXC_RETURN_MIN_MAGIC;
> +    }
> +
> +    if (dest >= min_magic) {
> +        /*
> +         * This is an exception return magic value; put it where
> +         * do_v7m_exception_exit() expects and raise EXCEPTION_EXIT.
> +         * Note that if we ever add gen_ss_advance() singlestep support to
> +         * M profile this should count as an "instruction execution complete"
> +         * event (compare gen_bx_excret_final_code()).
> +         */
> +        env->regs[15] = dest & ~1;
> +        env->thumb = dest & 1;
> +        HELPER(exception_internal)(env, EXCP_EXCEPTION_EXIT);
> +        /* notreached */
> +    }
> +
> +    /* translate.c should have made BXNS UNDEF unless we're secure */
> +    assert(env->v7m.secure);
> +
> +    if (!(dest & 1)) {
> +        env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_SFPA_MASK;
> +    }
> +    switch_v7m_security_state(env, dest & 1);
> +    env->thumb = 1;
> +    env->regs[15] = dest & ~1;
> +}
> +
> +void HELPER(v7m_blxns)(CPUARMState *env, uint32_t dest)
> +{
> +    /*
> +     * Handle v7M BLXNS:
> +     *  - bit 0 of the destination address is the target security state
> +     */
> +
> +    /* At this point regs[15] is the address just after the BLXNS */
> +    uint32_t nextinst = env->regs[15] | 1;
> +    uint32_t sp = env->regs[13] - 8;
> +    uint32_t saved_psr;
> +
> +    /* translate.c will have made BLXNS UNDEF unless we're secure */
> +    assert(env->v7m.secure);
> +
> +    if (dest & 1) {
> +        /*
> +         * Target is Secure, so this is just a normal BLX,
> +         * except that the low bit doesn't indicate Thumb/not.
> +         */
> +        env->regs[14] = nextinst;
> +        env->thumb = 1;
> +        env->regs[15] = dest & ~1;
> +        return;
> +    }
> +
> +    /* Target is non-secure: first push a stack frame */
> +    if (!QEMU_IS_ALIGNED(sp, 8)) {
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "BLXNS with misaligned SP is UNPREDICTABLE\n");
> +    }
> +
> +    if (sp < v7m_sp_limit(env)) {
> +        raise_exception(env, EXCP_STKOF, 0, 1);
> +    }
> +
> +    saved_psr = env->v7m.exception;
> +    if (env->v7m.control[M_REG_S] & R_V7M_CONTROL_SFPA_MASK) {
> +        saved_psr |= XPSR_SFPA;
> +    }
> +
> +    /* Note that these stores can throw exceptions on MPU faults */
> +    cpu_stl_data(env, sp, nextinst);
> +    cpu_stl_data(env, sp + 4, saved_psr);
> +
> +    env->regs[13] = sp;
> +    env->regs[14] = 0xfeffffff;
> +    if (arm_v7m_is_handler_mode(env)) {
> +        /*
> +         * Write a dummy value to IPSR, to avoid leaking the current secure
> +         * exception number to non-secure code. This is guaranteed not
> +         * to cause write_v7m_exception() to actually change stacks.
> +         */
> +        write_v7m_exception(env, 1);
> +    }
> +    env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_SFPA_MASK;
> +    switch_v7m_security_state(env, 0);
> +    env->thumb = 1;
> +    env->regs[15] = dest;
> +}
> +
> +uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg)
> +{
> +    uint32_t mask;
> +    unsigned el = arm_current_el(env);
> +
> +    /* First handle registers which unprivileged can read */
> +
> +    switch (reg) {
> +    case 0 ... 7: /* xPSR sub-fields */
> +        mask = 0;
> +        if ((reg & 1) && el) {
> +            mask |= XPSR_EXCP; /* IPSR (unpriv. reads as zero) */
> +        }
> +        if (!(reg & 4)) {
> +            mask |= XPSR_NZCV | XPSR_Q; /* APSR */
> +            if (arm_feature(env, ARM_FEATURE_THUMB_DSP)) {
> +                mask |= XPSR_GE;
> +            }
> +        }
> +        /* EPSR reads as zero */
> +        return xpsr_read(env) & mask;
> +        break;
> +    case 20: /* CONTROL */
> +    {
> +        uint32_t value = env->v7m.control[env->v7m.secure];
> +        if (!env->v7m.secure) {
> +            /* SFPA is RAZ/WI from NS; FPCA is stored in the M_REG_S bank */
> +            value |= env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK;
> +        }
> +        return value;
> +    }
> +    case 0x94: /* CONTROL_NS */
> +        /*
> +         * We have to handle this here because unprivileged Secure code
> +         * can read the NS CONTROL register.
> +         */
> +        if (!env->v7m.secure) {
> +            return 0;
> +        }
> +        return env->v7m.control[M_REG_NS] |
> +            (env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK);
> +    }
> +
> +    if (el == 0) {
> +        return 0; /* unprivileged reads others as zero */
> +    }
> +
> +    if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
> +        switch (reg) {
> +        case 0x88: /* MSP_NS */
> +            if (!env->v7m.secure) {
> +                return 0;
> +            }
> +            return env->v7m.other_ss_msp;
> +        case 0x89: /* PSP_NS */
> +            if (!env->v7m.secure) {
> +                return 0;
> +            }
> +            return env->v7m.other_ss_psp;
> +        case 0x8a: /* MSPLIM_NS */
> +            if (!env->v7m.secure) {
> +                return 0;
> +            }
> +            return env->v7m.msplim[M_REG_NS];
> +        case 0x8b: /* PSPLIM_NS */
> +            if (!env->v7m.secure) {
> +                return 0;
> +            }
> +            return env->v7m.psplim[M_REG_NS];
> +        case 0x90: /* PRIMASK_NS */
> +            if (!env->v7m.secure) {
> +                return 0;
> +            }
> +            return env->v7m.primask[M_REG_NS];
> +        case 0x91: /* BASEPRI_NS */
> +            if (!env->v7m.secure) {
> +                return 0;
> +            }
> +            return env->v7m.basepri[M_REG_NS];
> +        case 0x93: /* FAULTMASK_NS */
> +            if (!env->v7m.secure) {
> +                return 0;
> +            }
> +            return env->v7m.faultmask[M_REG_NS];
> +        case 0x98: /* SP_NS */
> +        {
> +            /*
> +             * This gives the non-secure SP selected based on whether we're
> +             * currently in handler mode or not, using the NS CONTROL.SPSEL.
> +             */
> +            bool spsel = env->v7m.control[M_REG_NS] & R_V7M_CONTROL_SPSEL_MASK;
> +
> +            if (!env->v7m.secure) {
> +                return 0;
> +            }
> +            if (!arm_v7m_is_handler_mode(env) && spsel) {
> +                return env->v7m.other_ss_psp;
> +            } else {
> +                return env->v7m.other_ss_msp;
> +            }
> +        }
> +        default:
> +            break;
> +        }
> +    }
> +
> +    switch (reg) {
> +    case 8: /* MSP */
> +        return v7m_using_psp(env) ? env->v7m.other_sp : env->regs[13];
> +    case 9: /* PSP */
> +        return v7m_using_psp(env) ? env->regs[13] : env->v7m.other_sp;
> +    case 10: /* MSPLIM */
> +        if (!arm_feature(env, ARM_FEATURE_V8)) {
> +            goto bad_reg;
> +        }
> +        return env->v7m.msplim[env->v7m.secure];
> +    case 11: /* PSPLIM */
> +        if (!arm_feature(env, ARM_FEATURE_V8)) {
> +            goto bad_reg;
> +        }
> +        return env->v7m.psplim[env->v7m.secure];
> +    case 16: /* PRIMASK */
> +        return env->v7m.primask[env->v7m.secure];
> +    case 17: /* BASEPRI */
> +    case 18: /* BASEPRI_MAX */
> +        return env->v7m.basepri[env->v7m.secure];
> +    case 19: /* FAULTMASK */
> +        return env->v7m.faultmask[env->v7m.secure];
> +    default:
> +    bad_reg:
> +        qemu_log_mask(LOG_GUEST_ERROR, "Attempt to read unknown special"
> +                                       " register %d\n", reg);
> +        return 0;
> +    }
> +}
> +
> +void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val)
> +{
> +    /*
> +     * We're passed bits [11..0] of the instruction; extract
> +     * SYSm and the mask bits.
> +     * Invalid combinations of SYSm and mask are UNPREDICTABLE;
> +     * we choose to treat them as if the mask bits were valid.
> +     * NB that the pseudocode 'mask' variable is bits [11..10],
> +     * whereas ours is [11..8].
> +     */
> +    uint32_t mask = extract32(maskreg, 8, 4);
> +    uint32_t reg = extract32(maskreg, 0, 8);
> +    int cur_el = arm_current_el(env);
> +
> +    if (cur_el == 0 && reg > 7 && reg != 20) {
> +        /*
> +         * only xPSR sub-fields and CONTROL.SFPA may be written by
> +         * unprivileged code
> +         */
> +        return;
> +    }
> +
> +    if (arm_feature(env, ARM_FEATURE_M_SECURITY)) {
> +        switch (reg) {
> +        case 0x88: /* MSP_NS */
> +            if (!env->v7m.secure) {
> +                return;
> +            }
> +            env->v7m.other_ss_msp = val;
> +            return;
> +        case 0x89: /* PSP_NS */
> +            if (!env->v7m.secure) {
> +                return;
> +            }
> +            env->v7m.other_ss_psp = val;
> +            return;
> +        case 0x8a: /* MSPLIM_NS */
> +            if (!env->v7m.secure) {
> +                return;
> +            }
> +            env->v7m.msplim[M_REG_NS] = val & ~7;
> +            return;
> +        case 0x8b: /* PSPLIM_NS */
> +            if (!env->v7m.secure) {
> +                return;
> +            }
> +            env->v7m.psplim[M_REG_NS] = val & ~7;
> +            return;
> +        case 0x90: /* PRIMASK_NS */
> +            if (!env->v7m.secure) {
> +                return;
> +            }
> +            env->v7m.primask[M_REG_NS] = val & 1;
> +            return;
> +        case 0x91: /* BASEPRI_NS */
> +            if (!env->v7m.secure || !arm_feature(env, ARM_FEATURE_M_MAIN)) {
> +                return;
> +            }
> +            env->v7m.basepri[M_REG_NS] = val & 0xff;
> +            return;
> +        case 0x93: /* FAULTMASK_NS */
> +            if (!env->v7m.secure || !arm_feature(env, ARM_FEATURE_M_MAIN)) {
> +                return;
> +            }
> +            env->v7m.faultmask[M_REG_NS] = val & 1;
> +            return;
> +        case 0x94: /* CONTROL_NS */
> +            if (!env->v7m.secure) {
> +                return;
> +            }
> +            write_v7m_control_spsel_for_secstate(env,
> +                                                 val & R_V7M_CONTROL_SPSEL_MASK,
> +                                                 M_REG_NS);
> +            if (arm_feature(env, ARM_FEATURE_M_MAIN)) {
> +                env->v7m.control[M_REG_NS] &= ~R_V7M_CONTROL_NPRIV_MASK;
> +                env->v7m.control[M_REG_NS] |= val & R_V7M_CONTROL_NPRIV_MASK;
> +            }
> +            /*
> +             * SFPA is RAZ/WI from NS. FPCA is RO if NSACR.CP10 == 0,
> +             * RES0 if the FPU is not present, and is stored in the S bank
> +             */
> +            if (arm_feature(env, ARM_FEATURE_VFP) &&
> +                extract32(env->v7m.nsacr, 10, 1)) {
> +                env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_FPCA_MASK;
> +                env->v7m.control[M_REG_S] |= val & R_V7M_CONTROL_FPCA_MASK;
> +            }
> +            return;
> +        case 0x98: /* SP_NS */
> +        {
> +            /*
> +             * This gives the non-secure SP selected based on whether we're
> +             * currently in handler mode or not, using the NS CONTROL.SPSEL.
> +             */
> +            bool spsel = env->v7m.control[M_REG_NS] & R_V7M_CONTROL_SPSEL_MASK;
> +            bool is_psp = !arm_v7m_is_handler_mode(env) && spsel;
> +            uint32_t limit;
> +
> +            if (!env->v7m.secure) {
> +                return;
> +            }
> +
> +            limit = is_psp ? env->v7m.psplim[false] : env->v7m.msplim[false];
> +
> +            if (val < limit) {
> +                CPUState *cs = env_cpu(env);
> +
> +                cpu_restore_state(cs, GETPC(), true);
> +                raise_exception(env, EXCP_STKOF, 0, 1);
> +            }
> +
> +            if (is_psp) {
> +                env->v7m.other_ss_psp = val;
> +            } else {
> +                env->v7m.other_ss_msp = val;
> +            }
> +            return;
> +        }
> +        default:
> +            break;
> +        }
> +    }
> +
> +    switch (reg) {
> +    case 0 ... 7: /* xPSR sub-fields */
> +        /* only APSR is actually writable */
> +        if (!(reg & 4)) {
> +            uint32_t apsrmask = 0;
> +
> +            if (mask & 8) {
> +                apsrmask |= XPSR_NZCV | XPSR_Q;
> +            }
> +            if ((mask & 4) && arm_feature(env, ARM_FEATURE_THUMB_DSP)) {
> +                apsrmask |= XPSR_GE;
> +            }
> +            xpsr_write(env, val, apsrmask);
> +        }
> +        break;
> +    case 8: /* MSP */
> +        if (v7m_using_psp(env)) {
> +            env->v7m.other_sp = val;
> +        } else {
> +            env->regs[13] = val;
> +        }
> +        break;
> +    case 9: /* PSP */
> +        if (v7m_using_psp(env)) {
> +            env->regs[13] = val;
> +        } else {
> +            env->v7m.other_sp = val;
> +        }
> +        break;
> +    case 10: /* MSPLIM */
> +        if (!arm_feature(env, ARM_FEATURE_V8)) {
> +            goto bad_reg;
> +        }
> +        env->v7m.msplim[env->v7m.secure] = val & ~7;
> +        break;
> +    case 11: /* PSPLIM */
> +        if (!arm_feature(env, ARM_FEATURE_V8)) {
> +            goto bad_reg;
> +        }
> +        env->v7m.psplim[env->v7m.secure] = val & ~7;
> +        break;
> +    case 16: /* PRIMASK */
> +        env->v7m.primask[env->v7m.secure] = val & 1;
> +        break;
> +    case 17: /* BASEPRI */
> +        if (!arm_feature(env, ARM_FEATURE_M_MAIN)) {
> +            goto bad_reg;
> +        }
> +        env->v7m.basepri[env->v7m.secure] = val & 0xff;
> +        break;
> +    case 18: /* BASEPRI_MAX */
> +        if (!arm_feature(env, ARM_FEATURE_M_MAIN)) {
> +            goto bad_reg;
> +        }
> +        val &= 0xff;
> +        if (val != 0 && (val < env->v7m.basepri[env->v7m.secure]
> +                         || env->v7m.basepri[env->v7m.secure] == 0)) {
> +            env->v7m.basepri[env->v7m.secure] = val;
> +        }
> +        break;
> +    case 19: /* FAULTMASK */
> +        if (!arm_feature(env, ARM_FEATURE_M_MAIN)) {
> +            goto bad_reg;
> +        }
> +        env->v7m.faultmask[env->v7m.secure] = val & 1;
> +        break;
> +    case 20: /* CONTROL */
> +        /*
> +         * Writing to the SPSEL bit only has an effect if we are in
> +         * thread mode; other bits can be updated by any privileged code.
> +         * write_v7m_control_spsel() deals with updating the SPSEL bit in
> +         * env->v7m.control, so we only need update the others.
> +         * For v7M, we must just ignore explicit writes to SPSEL in handler
> +         * mode; for v8M the write is permitted but will have no effect.
> +         * All these bits are writes-ignored from non-privileged code,
> +         * except for SFPA.
> +         */
> +        if (cur_el > 0 && (arm_feature(env, ARM_FEATURE_V8) ||
> +                           !arm_v7m_is_handler_mode(env))) {
> +            write_v7m_control_spsel(env, (val & R_V7M_CONTROL_SPSEL_MASK) != 0);
> +        }
> +        if (cur_el > 0 && arm_feature(env, ARM_FEATURE_M_MAIN)) {
> +            env->v7m.control[env->v7m.secure] &= ~R_V7M_CONTROL_NPRIV_MASK;
> +            env->v7m.control[env->v7m.secure] |= val & R_V7M_CONTROL_NPRIV_MASK;
> +        }
> +        if (arm_feature(env, ARM_FEATURE_VFP)) {
> +            /*
> +             * SFPA is RAZ/WI from NS or if no FPU.
> +             * FPCA is RO if NSACR.CP10 == 0, RES0 if the FPU is not present.
> +             * Both are stored in the S bank.
> +             */
> +            if (env->v7m.secure) {
> +                env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_SFPA_MASK;
> +                env->v7m.control[M_REG_S] |= val & R_V7M_CONTROL_SFPA_MASK;
> +            }
> +            if (cur_el > 0 &&
> +                (env->v7m.secure || !arm_feature(env, ARM_FEATURE_M_SECURITY) ||
> +                 extract32(env->v7m.nsacr, 10, 1))) {
> +                env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_FPCA_MASK;
> +                env->v7m.control[M_REG_S] |= val & R_V7M_CONTROL_FPCA_MASK;
> +            }
> +        }
> +        break;
> +    default:
> +    bad_reg:
> +        qemu_log_mask(LOG_GUEST_ERROR, "Attempt to write unknown special"
> +                                       " register %d\n", reg);
> +        return;
> +    }
> +}
> +
> +uint32_t HELPER(v7m_tt)(CPUARMState *env, uint32_t addr, uint32_t op)
> +{
> +    /* Implement the TT instruction. op is bits [7:6] of the insn. */
> +    bool forceunpriv = op & 1;
> +    bool alt = op & 2;
> +    V8M_SAttributes sattrs = {};
> +    uint32_t tt_resp;
> +    bool r, rw, nsr, nsrw, mrvalid;
> +    int prot;
> +    ARMMMUFaultInfo fi = {};
> +    MemTxAttrs attrs = {};
> +    hwaddr phys_addr;
> +    ARMMMUIdx mmu_idx;
> +    uint32_t mregion;
> +    bool targetpriv;
> +    bool targetsec = env->v7m.secure;
> +    bool is_subpage;
> +
> +    /*
> +     * Work out what the security state and privilege level we're
> +     * interested in is...
> +     */
> +    if (alt) {
> +        targetsec = !targetsec;
> +    }
> +
> +    if (forceunpriv) {
> +        targetpriv = false;
> +    } else {
> +        targetpriv = arm_v7m_is_handler_mode(env) ||
> +            !(env->v7m.control[targetsec] & R_V7M_CONTROL_NPRIV_MASK);
> +    }
> +
> +    /* ...and then figure out which MMU index this is */
> +    mmu_idx = arm_v7m_mmu_idx_for_secstate_and_priv(env, targetsec, targetpriv);
> +
> +    /*
> +     * We know that the MPU and SAU don't care about the access type
> +     * for our purposes beyond that we don't want to claim to be
> +     * an insn fetch, so we arbitrarily call this a read.
> +     */
> +
> +    /*
> +     * MPU region info only available for privileged or if
> +     * inspecting the other MPU state.
> +     */
> +    if (arm_current_el(env) != 0 || alt) {
> +        /* We can ignore the return value as prot is always set */
> +        pmsav8_mpu_lookup(env, addr, MMU_DATA_LOAD, mmu_idx,
> +                          &phys_addr, &attrs, &prot, &is_subpage,
> +                          &fi, &mregion);
> +        if (mregion == -1) {
> +            mrvalid = false;
> +            mregion = 0;
> +        } else {
> +            mrvalid = true;
> +        }
> +        r = prot & PAGE_READ;
> +        rw = prot & PAGE_WRITE;
> +    } else {
> +        r = false;
> +        rw = false;
> +        mrvalid = false;
> +        mregion = 0;
> +    }
> +
> +    if (env->v7m.secure) {
> +        v8m_security_lookup(env, addr, MMU_DATA_LOAD, mmu_idx, &sattrs);
> +        nsr = sattrs.ns && r;
> +        nsrw = sattrs.ns && rw;
> +    } else {
> +        sattrs.ns = true;
> +        nsr = false;
> +        nsrw = false;
> +    }
> +
> +    tt_resp = (sattrs.iregion << 24) |
> +        (sattrs.irvalid << 23) |
> +        ((!sattrs.ns) << 22) |
> +        (nsrw << 21) |
> +        (nsr << 20) |
> +        (rw << 19) |
> +        (r << 18) |
> +        (sattrs.srvalid << 17) |
> +        (mrvalid << 16) |
> +        (sattrs.sregion << 8) |
> +        mregion;
> +
> +    return tt_resp;
> +}
> +
> +#endif /* CONFIG_USER_ONLY */


--
Alex Bennée


  reply	other threads:[~2019-06-17 12:11 UTC|newest]

Thread overview: 51+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-06-15 15:43 [Qemu-devel] [PATCH v2 00/23] Support disabling TCG on ARM Philippe Mathieu-Daudé
2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 01/23] target/arm: Makefile cleanup (Aarch64) Philippe Mathieu-Daudé
2019-06-17 11:36   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 02/23] target/arm: Makefile cleanup (ARM) Philippe Mathieu-Daudé
2019-06-17 11:36   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
2019-06-17 11:37   ` Alex Bennée
2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 03/23] target/arm: Makefile cleanup (KVM) Philippe Mathieu-Daudé
2019-06-17 11:37   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 04/23] target/arm: Makefile cleanup (softmmu) Philippe Mathieu-Daudé
2019-06-17 11:38   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 05/23] target/arm: Add copyright boilerplate Philippe Mathieu-Daudé
2019-06-17 11:39   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 06/23] target/arm: Fix multiline comment syntax Philippe Mathieu-Daudé
2019-06-17 11:40   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 07/23] target/arm: Declare some function publicly Philippe Mathieu-Daudé
2019-06-17 14:07   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 08/23] target/arm: Move all v7m insn helpers into their own file Philippe Mathieu-Daudé
2019-06-17 11:42   ` Alex Bennée [this message]
2019-06-17 12:12     ` Philippe Mathieu-Daudé
2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 09/23] target/arm: Move code around Philippe Mathieu-Daudé
2019-06-17 14:07   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 10/23] target/arm: Move the v7-M Security State helpers to v7m_helper Philippe Mathieu-Daudé
2019-06-17 14:08   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 11/23] target/arm: Declare v7m_cpacr_pass() publicly Philippe Mathieu-Daudé
2019-06-17 14:09   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 12/23] target/arm: Move v7m exception handling routines to v7m_helper Philippe Mathieu-Daudé
2019-06-17 14:10   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 13/23] target/arm: Make the v7-M Security State routines Philippe Mathieu-Daudé
2019-06-17 14:11   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 14/23] target/arm: Move the DC ZVA helper into op_helper Philippe Mathieu-Daudé
2019-06-17 14:12   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 15/23] target/arm: Make ARM TLB filling routine static Philippe Mathieu-Daudé
2019-06-17 14:16   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 16/23] target/arm: Make arm_deliver_fault() static Philippe Mathieu-Daudé
2019-06-17 14:19   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 17/23] target/arm: Fix coding style issues Philippe Mathieu-Daudé
2019-06-17 14:20   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 18/23] target/arm: Move CPU state dumping routines to helper.c Philippe Mathieu-Daudé
2019-06-17 14:41   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
2019-06-17 14:45     ` Philippe Mathieu-Daudé
2019-06-17 14:52     ` Peter Maydell
2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 19/23] target/arm: Move watchpoints APIs " Philippe Mathieu-Daudé
2019-06-17 14:46   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 20/23] target/arm: Define TCG dependent functions when TCG is enabled Philippe Mathieu-Daudé
2019-06-17 14:50   ` Alex Bennée
2019-06-15 15:43 ` [Qemu-devel] [PATCH v2 21/23] target/arm: Do not build TCG objects when TCG is off Philippe Mathieu-Daudé
2019-06-17 14:49   ` [Qemu-devel] [Qemu-arm] " Alex Bennée
2019-06-15 15:43 ` [Qemu-devel] [RFC PATCH v2 22/23] target/arm: Restrict semi-hosting to TCG Philippe Mathieu-Daudé
2019-06-17 14:07   ` Alex Bennée
2019-06-15 15:43 ` [Qemu-devel] [NOTFORMERGE PATCH v2 23/23] Missing symbols when building with --disable-tcg Philippe Mathieu-Daudé
2019-06-17 14:04   ` [Qemu-devel] [Qemu-arm] " Alex Bennée

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=8736k8bfph.fsf@zen.linaroharston \
    --to=alex.bennee@linaro.org \
    --cc=peter.maydell@linaro.org \
    --cc=philmd@redhat.com \
    --cc=qemu-arm@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    --cc=sameo@linux.intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.