From: "Edgar E. Iglesias" <edgar.iglesias@gmail.com>
To: Peter Maydell <peter.maydell@linaro.org>
Cc: qemu-arm@nongnu.org, qemu-devel@nongnu.org
Subject: Re: [Qemu-arm] [PATCH] target-arm: Implement MRS (banked) and MSR (banked) instructions
Date: Mon, 29 Feb 2016 22:22:39 +0100 [thread overview]
Message-ID: <20160229212239.GF16305@toto> (raw)
In-Reply-To: <1456762734-23939-1-git-send-email-peter.maydell@linaro.org>
On Mon, Feb 29, 2016 at 04:18:54PM +0000, Peter Maydell wrote:
> Starting with the ARMv7 Virtualization Extensions, the A32 and T32
> instruction sets provide instructions "MSR (banked)" and "MRS
> (banked)" which can be used to access registers for a mode other
> than the current one:
> * R<m>_<mode>
> * ELR_hyp
> * SPSR_<mode>
>
> Implement the missing instructions.
Wow, these insns were a bit messy to follow... Anyway, AFAIK this looks OK:
Acked-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
> We don't support EL2 yet, but you can get at these on a v8 CPU in
> 32-bit EL1 if EL3 is enabled. Obviously there's not going to be much
> 32-bit EL1 code out there that uses the insns though, as it wouldn't
> work on v7 if it did...
>
> target-arm/helper.h | 3 +
> target-arm/op_helper.c | 120 ++++++++++++++++++++++++
> target-arm/translate.c | 246 ++++++++++++++++++++++++++++++++++++++++++++++++-
> 3 files changed, 366 insertions(+), 3 deletions(-)
>
> diff --git a/target-arm/helper.h b/target-arm/helper.h
> index ea13202..de3c644 100644
> --- a/target-arm/helper.h
> +++ b/target-arm/helper.h
> @@ -76,6 +76,9 @@ DEF_HELPER_1(exception_return, void, env)
> DEF_HELPER_2(get_r13_banked, i32, env, i32)
> DEF_HELPER_3(set_r13_banked, void, env, i32, i32)
>
> +DEF_HELPER_3(mrs_banked, i32, env, i32, i32)
> +DEF_HELPER_4(msr_banked, void, env, i32, i32, i32)
> +
> DEF_HELPER_2(get_user_reg, i32, env, i32)
> DEF_HELPER_3(set_user_reg, void, env, i32, i32)
>
> diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
> index 4881e34..a2afdd8 100644
> --- a/target-arm/op_helper.c
> +++ b/target-arm/op_helper.c
> @@ -489,6 +489,126 @@ uint32_t HELPER(get_r13_banked)(CPUARMState *env, uint32_t mode)
> }
> }
>
> +static void msr_mrs_banked_exc_checks(CPUARMState *env, uint32_t tgtmode,
> + uint32_t regno)
> +{
> + /* Raise an exception if the requested access is one of the UNPREDICTABLE
> + * cases; otherwise return. This broadly corresponds to the pseudocode
> + * BankedRegisterAccessValid() and SPSRAccessValid(),
> + * except that we have already handled some cases at translate time.
> + */
> + int curmode = env->uncached_cpsr & CPSR_M;
> +
> + if (curmode == tgtmode) {
> + goto undef;
> + }
> +
> + if (tgtmode == ARM_CPU_MODE_USR) {
> + switch (regno) {
> + case 8 ... 12:
> + if (curmode != ARM_CPU_MODE_FIQ) {
> + goto undef;
> + }
> + break;
> + case 13:
> + if (curmode == ARM_CPU_MODE_SYS) {
> + goto undef;
> + }
> + break;
> + case 14:
> + if (curmode == ARM_CPU_MODE_HYP || curmode == ARM_CPU_MODE_SYS) {
> + goto undef;
> + }
> + break;
> + default:
> + break;
> + }
> + }
> +
> + if (tgtmode == ARM_CPU_MODE_HYP) {
> + switch (regno) {
> + case 17: /* ELR_Hyp */
> + if (curmode != ARM_CPU_MODE_HYP && curmode != ARM_CPU_MODE_MON) {
> + goto undef;
> + }
> + break;
> + default:
> + if (curmode != ARM_CPU_MODE_MON) {
> + goto undef;
> + }
> + break;
> + }
> + }
> +
> + return;
> +
> +undef:
> + raise_exception(env, EXCP_UDEF, syn_uncategorized(),
> + exception_target_el(env));
> +}
> +
> +void HELPER(msr_banked)(CPUARMState *env, uint32_t value, uint32_t tgtmode,
> + uint32_t regno)
> +{
> + msr_mrs_banked_exc_checks(env, tgtmode, regno);
> +
> + switch (regno) {
> + case 16: /* SPSRs */
> + env->banked_spsr[bank_number(tgtmode)] = value;
> + break;
> + case 17: /* ELR_Hyp */
> + env->elr_el[2] = value;
> + break;
> + case 13:
> + env->banked_r13[bank_number(tgtmode)] = value;
> + break;
> + case 14:
> + env->banked_r14[bank_number(tgtmode)] = value;
> + break;
> + case 8 ... 12:
> + switch (tgtmode) {
> + case ARM_CPU_MODE_USR:
> + env->usr_regs[regno - 8] = value;
> + break;
> + case ARM_CPU_MODE_FIQ:
> + env->fiq_regs[regno - 8] = value;
> + break;
> + default:
> + g_assert_not_reached();
> + }
> + break;
> + default:
> + g_assert_not_reached();
> + }
> +}
> +
> +uint32_t HELPER(mrs_banked)(CPUARMState *env, uint32_t tgtmode, uint32_t regno)
> +{
> + msr_mrs_banked_exc_checks(env, tgtmode, regno);
> +
> + switch (regno) {
> + case 16: /* SPSRs */
> + return env->banked_spsr[bank_number(tgtmode)];
> + case 17: /* ELR_Hyp */
> + return env->elr_el[2];
> + case 13:
> + return env->banked_r13[bank_number(tgtmode)];
> + case 14:
> + return env->banked_r14[bank_number(tgtmode)];
> + case 8 ... 12:
> + switch (tgtmode) {
> + case ARM_CPU_MODE_USR:
> + return env->usr_regs[regno - 8];
> + case ARM_CPU_MODE_FIQ:
> + return env->fiq_regs[regno - 8];
> + default:
> + g_assert_not_reached();
> + }
> + default:
> + g_assert_not_reached();
> + }
> +}
> +
> void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip, uint32_t syndrome,
> uint32_t isread)
> {
> diff --git a/target-arm/translate.c b/target-arm/translate.c
> index 413f7de..a8dd490 100644
> --- a/target-arm/translate.c
> +++ b/target-arm/translate.c
> @@ -4088,6 +4088,195 @@ static int gen_set_psr_im(DisasContext *s, uint32_t mask, int spsr, uint32_t val
> return gen_set_psr(s, mask, spsr, tmp);
> }
>
> +static bool msr_banked_access_decode(DisasContext *s, int r, int sysm, int rn,
> + int *tgtmode, int *regno)
> +{
> + /* Decode the r and sysm fields of MSR/MRS banked accesses into
> + * the target mode and register number, and identify the various
> + * unpredictable cases.
> + * MSR (banked) and MRS (banked) are CONSTRAINED UNPREDICTABLE if:
> + * + executed in user mode
> + * + using R15 as the src/dest register
> + * + accessing an unimplemented register
> + * + accessing a register that's inaccessible at current PL/security state*
> + * + accessing a register that you could access with a different insn
> + * We choose to UNDEF in all these cases.
> + * Since we don't know which of the various AArch32 modes we are in
> + * we have to defer some checks to runtime.
> + * Accesses to Monitor mode registers from Secure EL1 (which implies
> + * that EL3 is AArch64) must trap to EL3.
> + *
> + * If the access checks fail this function will emit code to take
> + * an exception and return false. Otherwise it will return true,
> + * and set *tgtmode and *regno appropriately.
> + */
> + int exc_target = default_exception_el(s);
> +
> + /* These instructions are present only in ARMv8, or in ARMv7 with the
> + * Virtualization Extensions.
> + */
> + if (!arm_dc_feature(s, ARM_FEATURE_V8) &&
> + !arm_dc_feature(s, ARM_FEATURE_EL2)) {
> + goto undef;
> + }
> +
> + if (IS_USER(s) || rn == 15) {
> + goto undef;
> + }
> +
> + /* The table in the v8 ARM ARM section F5.2.3 describes the encoding
> + * of registers into (r, sysm).
> + */
> + if (r) {
> + /* SPSRs for other modes */
> + switch (sysm) {
> + case 0xe: /* SPSR_fiq */
> + *tgtmode = ARM_CPU_MODE_FIQ;
> + break;
> + case 0x10: /* SPSR_irq */
> + *tgtmode = ARM_CPU_MODE_IRQ;
> + break;
> + case 0x12: /* SPSR_svc */
> + *tgtmode = ARM_CPU_MODE_SVC;
> + break;
> + case 0x14: /* SPSR_abt */
> + *tgtmode = ARM_CPU_MODE_ABT;
> + break;
> + case 0x16: /* SPSR_und */
> + *tgtmode = ARM_CPU_MODE_UND;
> + break;
> + case 0x1c: /* SPSR_mon */
> + *tgtmode = ARM_CPU_MODE_MON;
> + break;
> + case 0x1e: /* SPSR_hyp */
> + *tgtmode = ARM_CPU_MODE_HYP;
> + break;
> + default: /* unallocated */
> + goto undef;
> + }
> + /* We arbitrarily assign SPSR a register number of 16. */
> + *regno = 16;
> + } else {
> + /* general purpose registers for other modes */
> + switch (sysm) {
> + case 0x0 ... 0x6: /* 0b00xxx : r8_usr ... r14_usr */
> + *tgtmode = ARM_CPU_MODE_USR;
> + *regno = sysm + 8;
> + break;
> + case 0x8 ... 0xe: /* 0b01xxx : r8_fiq ... r14_fiq */
> + *tgtmode = ARM_CPU_MODE_FIQ;
> + *regno = sysm;
> + break;
> + case 0x10 ... 0x11: /* 0b1000x : r14_irq, r13_irq */
> + *tgtmode = ARM_CPU_MODE_IRQ;
> + *regno = sysm & 1 ? 13 : 14;
> + break;
> + case 0x12 ... 0x13: /* 0b1001x : r14_svc, r13_svc */
> + *tgtmode = ARM_CPU_MODE_SVC;
> + *regno = sysm & 1 ? 13 : 14;
> + break;
> + case 0x14 ... 0x15: /* 0b1010x : r14_abt, r13_abt */
> + *tgtmode = ARM_CPU_MODE_ABT;
> + *regno = sysm & 1 ? 13 : 14;
> + break;
> + case 0x16 ... 0x17: /* 0b1011x : r14_und, r13_und */
> + *tgtmode = ARM_CPU_MODE_UND;
> + *regno = sysm & 1 ? 13 : 14;
> + break;
> + case 0x1c ... 0x1d: /* 0b1110x : r14_mon, r13_mon */
> + *tgtmode = ARM_CPU_MODE_MON;
> + *regno = sysm & 1 ? 13 : 14;
> + break;
> + case 0x1e ... 0x1f: /* 0b1111x : elr_hyp, r13_hyp */
> + *tgtmode = ARM_CPU_MODE_HYP;
> + /* Arbitrarily pick 17 for ELR_Hyp (which is not a banked LR!) */
> + *regno = sysm & 1 ? 13 : 17;
> + break;
> + default: /* unallocated */
> + goto undef;
> + }
> + }
> +
> + /* Catch the 'accessing inaccessible register' cases we can detect
> + * at translate time.
> + */
> + switch (*tgtmode) {
> + case ARM_CPU_MODE_MON:
> + if (!arm_dc_feature(s, ARM_FEATURE_EL3) || s->ns) {
> + goto undef;
> + }
> + if (s->current_el == 1) {
> + /* If we're in Secure EL1 (which implies that EL3 is AArch64)
> + * then accesses to Mon registers trap to EL3
> + */
> + exc_target = 3;
> + goto undef;
> + }
> + break;
> + case ARM_CPU_MODE_HYP:
> + /* Note that we can forbid accesses from EL2 here because they
> + * must be from Hyp mode itself
> + */
> + if (!arm_dc_feature(s, ARM_FEATURE_EL2) || s->current_el < 3) {
> + goto undef;
> + }
> + break;
> + default:
> + break;
> + }
> +
> + return true;
> +
> +undef:
> + /* If we get here then some access check did not pass */
> + gen_exception_insn(s, 4, EXCP_UDEF, syn_uncategorized(), exc_target);
> + return false;
> +}
> +
> +static void gen_msr_banked(DisasContext *s, int r, int sysm, int rn)
> +{
> + TCGv_i32 tcg_reg, tcg_tgtmode, tcg_regno;
> + int tgtmode, regno;
> +
> + if (!msr_banked_access_decode(s, r, sysm, rn, &tgtmode, ®no)) {
> + return;
> + }
> +
> + /* Sync state because msr_banked() can raise exceptions */
> + gen_set_condexec(s);
> + gen_set_pc_im(s, s->pc - 4);
> + tcg_reg = load_reg(s, rn);
> + tcg_tgtmode = tcg_const_i32(tgtmode);
> + tcg_regno = tcg_const_i32(regno);
> + gen_helper_msr_banked(cpu_env, tcg_reg, tcg_tgtmode, tcg_regno);
> + tcg_temp_free_i32(tcg_tgtmode);
> + tcg_temp_free_i32(tcg_regno);
> + tcg_temp_free_i32(tcg_reg);
> + s->is_jmp = DISAS_UPDATE;
> +}
> +
> +static void gen_mrs_banked(DisasContext *s, int r, int sysm, int rn)
> +{
> + TCGv_i32 tcg_reg, tcg_tgtmode, tcg_regno;
> + int tgtmode, regno;
> +
> + if (!msr_banked_access_decode(s, r, sysm, rn, &tgtmode, ®no)) {
> + return;
> + }
> +
> + /* Sync state because mrs_banked() can raise exceptions */
> + gen_set_condexec(s);
> + gen_set_pc_im(s, s->pc - 4);
> + tcg_reg = tcg_temp_new_i32();
> + tcg_tgtmode = tcg_const_i32(tgtmode);
> + tcg_regno = tcg_const_i32(regno);
> + gen_helper_mrs_banked(tcg_reg, cpu_env, tcg_tgtmode, tcg_regno);
> + tcg_temp_free_i32(tcg_tgtmode);
> + tcg_temp_free_i32(tcg_regno);
> + store_reg(s, rn, tcg_reg);
> + s->is_jmp = DISAS_UPDATE;
> +}
> +
> /* Generate an old-style exception return. Marks pc as dead. */
> static void gen_exception_return(DisasContext *s, TCGv_i32 pc)
> {
> @@ -7950,7 +8139,26 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
> sh = (insn >> 4) & 0xf;
> rm = insn & 0xf;
> switch (sh) {
> - case 0x0: /* move program status register */
> + case 0x0: /* MSR, MRS */
> + if (insn & (1 << 9)) {
> + /* MSR (banked) and MRS (banked) */
> + int sysm = extract32(insn, 16, 4) |
> + (extract32(insn, 8, 1) << 4);
> + int r = extract32(insn, 22, 1);
> +
> + if (op1 & 1) {
> + /* MSR (banked) */
> + gen_msr_banked(s, r, sysm, rm);
> + } else {
> + /* MRS (banked) */
> + int rd = extract32(insn, 12, 4);
> +
> + gen_mrs_banked(s, r, sysm, rd);
> + }
> + break;
> + }
> +
> + /* MSR, MRS (for PSRs) */
> if (op1 & 1) {
> /* PSR = reg */
> tmp = load_reg(s, rm);
> @@ -10055,6 +10263,18 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
> if (arm_dc_feature(s, ARM_FEATURE_M)) {
> goto illegal_op;
> }
> +
> + if (extract32(insn, 5, 1)) {
> + /* MSR (banked) */
> + int sysm = extract32(insn, 8, 4) |
> + (extract32(insn, 4, 1) << 4);
> + int r = op & 1;
> +
> + gen_msr_banked(s, r, sysm, rm);
> + break;
> + }
> +
> + /* MSR (for PSRs) */
> tmp = load_reg(s, rn);
> if (gen_set_psr(s,
> msr_mask(s, (insn >> 8) & 0xf, op == 1),
> @@ -10127,7 +10347,17 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
> tcg_gen_subi_i32(tmp, tmp, insn & 0xff);
> gen_exception_return(s, tmp);
> break;
> - case 6: /* mrs cpsr. */
> + case 6: /* MRS */
> + if (extract32(insn, 5, 1)) {
> + /* MRS (banked) */
> + int sysm = extract32(insn, 16, 4) |
> + (extract32(insn, 4, 1) << 4);
> +
> + gen_mrs_banked(s, 0, sysm, rd);
> + break;
> + }
> +
> + /* mrs cpsr */
> tmp = tcg_temp_new_i32();
> if (arm_dc_feature(s, ARM_FEATURE_M)) {
> addr = tcg_const_i32(insn & 0xff);
> @@ -10138,7 +10368,17 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
> }
> store_reg(s, rd, tmp);
> break;
> - case 7: /* mrs spsr. */
> + case 7: /* MRS */
> + if (extract32(insn, 5, 1)) {
> + /* MRS (banked) */
> + int sysm = extract32(insn, 16, 4) |
> + (extract32(insn, 4, 1) << 4);
> +
> + gen_mrs_banked(s, 1, sysm, rd);
> + break;
> + }
> +
> + /* mrs spsr. */
> /* Not accessible in user mode. */
> if (IS_USER(s) || arm_dc_feature(s, ARM_FEATURE_M)) {
> goto illegal_op;
> --
> 1.9.1
>
WARNING: multiple messages have this Message-ID (diff)
From: "Edgar E. Iglesias" <edgar.iglesias@gmail.com>
To: Peter Maydell <peter.maydell@linaro.org>
Cc: Sergey Fedorov <serge.fdrv@gmail.com>,
qemu-arm@nongnu.org, qemu-devel@nongnu.org
Subject: Re: [Qemu-devel] [PATCH] target-arm: Implement MRS (banked) and MSR (banked) instructions
Date: Mon, 29 Feb 2016 22:22:39 +0100 [thread overview]
Message-ID: <20160229212239.GF16305@toto> (raw)
In-Reply-To: <1456762734-23939-1-git-send-email-peter.maydell@linaro.org>
On Mon, Feb 29, 2016 at 04:18:54PM +0000, Peter Maydell wrote:
> Starting with the ARMv7 Virtualization Extensions, the A32 and T32
> instruction sets provide instructions "MSR (banked)" and "MRS
> (banked)" which can be used to access registers for a mode other
> than the current one:
> * R<m>_<mode>
> * ELR_hyp
> * SPSR_<mode>
>
> Implement the missing instructions.
Wow, these insns were a bit messy to follow... Anyway, AFAIK this looks OK:
Acked-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
> We don't support EL2 yet, but you can get at these on a v8 CPU in
> 32-bit EL1 if EL3 is enabled. Obviously there's not going to be much
> 32-bit EL1 code out there that uses the insns though, as it wouldn't
> work on v7 if it did...
>
> target-arm/helper.h | 3 +
> target-arm/op_helper.c | 120 ++++++++++++++++++++++++
> target-arm/translate.c | 246 ++++++++++++++++++++++++++++++++++++++++++++++++-
> 3 files changed, 366 insertions(+), 3 deletions(-)
>
> diff --git a/target-arm/helper.h b/target-arm/helper.h
> index ea13202..de3c644 100644
> --- a/target-arm/helper.h
> +++ b/target-arm/helper.h
> @@ -76,6 +76,9 @@ DEF_HELPER_1(exception_return, void, env)
> DEF_HELPER_2(get_r13_banked, i32, env, i32)
> DEF_HELPER_3(set_r13_banked, void, env, i32, i32)
>
> +DEF_HELPER_3(mrs_banked, i32, env, i32, i32)
> +DEF_HELPER_4(msr_banked, void, env, i32, i32, i32)
> +
> DEF_HELPER_2(get_user_reg, i32, env, i32)
> DEF_HELPER_3(set_user_reg, void, env, i32, i32)
>
> diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
> index 4881e34..a2afdd8 100644
> --- a/target-arm/op_helper.c
> +++ b/target-arm/op_helper.c
> @@ -489,6 +489,126 @@ uint32_t HELPER(get_r13_banked)(CPUARMState *env, uint32_t mode)
> }
> }
>
> +static void msr_mrs_banked_exc_checks(CPUARMState *env, uint32_t tgtmode,
> + uint32_t regno)
> +{
> + /* Raise an exception if the requested access is one of the UNPREDICTABLE
> + * cases; otherwise return. This broadly corresponds to the pseudocode
> + * BankedRegisterAccessValid() and SPSRAccessValid(),
> + * except that we have already handled some cases at translate time.
> + */
> + int curmode = env->uncached_cpsr & CPSR_M;
> +
> + if (curmode == tgtmode) {
> + goto undef;
> + }
> +
> + if (tgtmode == ARM_CPU_MODE_USR) {
> + switch (regno) {
> + case 8 ... 12:
> + if (curmode != ARM_CPU_MODE_FIQ) {
> + goto undef;
> + }
> + break;
> + case 13:
> + if (curmode == ARM_CPU_MODE_SYS) {
> + goto undef;
> + }
> + break;
> + case 14:
> + if (curmode == ARM_CPU_MODE_HYP || curmode == ARM_CPU_MODE_SYS) {
> + goto undef;
> + }
> + break;
> + default:
> + break;
> + }
> + }
> +
> + if (tgtmode == ARM_CPU_MODE_HYP) {
> + switch (regno) {
> + case 17: /* ELR_Hyp */
> + if (curmode != ARM_CPU_MODE_HYP && curmode != ARM_CPU_MODE_MON) {
> + goto undef;
> + }
> + break;
> + default:
> + if (curmode != ARM_CPU_MODE_MON) {
> + goto undef;
> + }
> + break;
> + }
> + }
> +
> + return;
> +
> +undef:
> + raise_exception(env, EXCP_UDEF, syn_uncategorized(),
> + exception_target_el(env));
> +}
> +
> +void HELPER(msr_banked)(CPUARMState *env, uint32_t value, uint32_t tgtmode,
> + uint32_t regno)
> +{
> + msr_mrs_banked_exc_checks(env, tgtmode, regno);
> +
> + switch (regno) {
> + case 16: /* SPSRs */
> + env->banked_spsr[bank_number(tgtmode)] = value;
> + break;
> + case 17: /* ELR_Hyp */
> + env->elr_el[2] = value;
> + break;
> + case 13:
> + env->banked_r13[bank_number(tgtmode)] = value;
> + break;
> + case 14:
> + env->banked_r14[bank_number(tgtmode)] = value;
> + break;
> + case 8 ... 12:
> + switch (tgtmode) {
> + case ARM_CPU_MODE_USR:
> + env->usr_regs[regno - 8] = value;
> + break;
> + case ARM_CPU_MODE_FIQ:
> + env->fiq_regs[regno - 8] = value;
> + break;
> + default:
> + g_assert_not_reached();
> + }
> + break;
> + default:
> + g_assert_not_reached();
> + }
> +}
> +
> +uint32_t HELPER(mrs_banked)(CPUARMState *env, uint32_t tgtmode, uint32_t regno)
> +{
> + msr_mrs_banked_exc_checks(env, tgtmode, regno);
> +
> + switch (regno) {
> + case 16: /* SPSRs */
> + return env->banked_spsr[bank_number(tgtmode)];
> + case 17: /* ELR_Hyp */
> + return env->elr_el[2];
> + case 13:
> + return env->banked_r13[bank_number(tgtmode)];
> + case 14:
> + return env->banked_r14[bank_number(tgtmode)];
> + case 8 ... 12:
> + switch (tgtmode) {
> + case ARM_CPU_MODE_USR:
> + return env->usr_regs[regno - 8];
> + case ARM_CPU_MODE_FIQ:
> + return env->fiq_regs[regno - 8];
> + default:
> + g_assert_not_reached();
> + }
> + default:
> + g_assert_not_reached();
> + }
> +}
> +
> void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip, uint32_t syndrome,
> uint32_t isread)
> {
> diff --git a/target-arm/translate.c b/target-arm/translate.c
> index 413f7de..a8dd490 100644
> --- a/target-arm/translate.c
> +++ b/target-arm/translate.c
> @@ -4088,6 +4088,195 @@ static int gen_set_psr_im(DisasContext *s, uint32_t mask, int spsr, uint32_t val
> return gen_set_psr(s, mask, spsr, tmp);
> }
>
> +static bool msr_banked_access_decode(DisasContext *s, int r, int sysm, int rn,
> + int *tgtmode, int *regno)
> +{
> + /* Decode the r and sysm fields of MSR/MRS banked accesses into
> + * the target mode and register number, and identify the various
> + * unpredictable cases.
> + * MSR (banked) and MRS (banked) are CONSTRAINED UNPREDICTABLE if:
> + * + executed in user mode
> + * + using R15 as the src/dest register
> + * + accessing an unimplemented register
> + * + accessing a register that's inaccessible at current PL/security state*
> + * + accessing a register that you could access with a different insn
> + * We choose to UNDEF in all these cases.
> + * Since we don't know which of the various AArch32 modes we are in
> + * we have to defer some checks to runtime.
> + * Accesses to Monitor mode registers from Secure EL1 (which implies
> + * that EL3 is AArch64) must trap to EL3.
> + *
> + * If the access checks fail this function will emit code to take
> + * an exception and return false. Otherwise it will return true,
> + * and set *tgtmode and *regno appropriately.
> + */
> + int exc_target = default_exception_el(s);
> +
> + /* These instructions are present only in ARMv8, or in ARMv7 with the
> + * Virtualization Extensions.
> + */
> + if (!arm_dc_feature(s, ARM_FEATURE_V8) &&
> + !arm_dc_feature(s, ARM_FEATURE_EL2)) {
> + goto undef;
> + }
> +
> + if (IS_USER(s) || rn == 15) {
> + goto undef;
> + }
> +
> + /* The table in the v8 ARM ARM section F5.2.3 describes the encoding
> + * of registers into (r, sysm).
> + */
> + if (r) {
> + /* SPSRs for other modes */
> + switch (sysm) {
> + case 0xe: /* SPSR_fiq */
> + *tgtmode = ARM_CPU_MODE_FIQ;
> + break;
> + case 0x10: /* SPSR_irq */
> + *tgtmode = ARM_CPU_MODE_IRQ;
> + break;
> + case 0x12: /* SPSR_svc */
> + *tgtmode = ARM_CPU_MODE_SVC;
> + break;
> + case 0x14: /* SPSR_abt */
> + *tgtmode = ARM_CPU_MODE_ABT;
> + break;
> + case 0x16: /* SPSR_und */
> + *tgtmode = ARM_CPU_MODE_UND;
> + break;
> + case 0x1c: /* SPSR_mon */
> + *tgtmode = ARM_CPU_MODE_MON;
> + break;
> + case 0x1e: /* SPSR_hyp */
> + *tgtmode = ARM_CPU_MODE_HYP;
> + break;
> + default: /* unallocated */
> + goto undef;
> + }
> + /* We arbitrarily assign SPSR a register number of 16. */
> + *regno = 16;
> + } else {
> + /* general purpose registers for other modes */
> + switch (sysm) {
> + case 0x0 ... 0x6: /* 0b00xxx : r8_usr ... r14_usr */
> + *tgtmode = ARM_CPU_MODE_USR;
> + *regno = sysm + 8;
> + break;
> + case 0x8 ... 0xe: /* 0b01xxx : r8_fiq ... r14_fiq */
> + *tgtmode = ARM_CPU_MODE_FIQ;
> + *regno = sysm;
> + break;
> + case 0x10 ... 0x11: /* 0b1000x : r14_irq, r13_irq */
> + *tgtmode = ARM_CPU_MODE_IRQ;
> + *regno = sysm & 1 ? 13 : 14;
> + break;
> + case 0x12 ... 0x13: /* 0b1001x : r14_svc, r13_svc */
> + *tgtmode = ARM_CPU_MODE_SVC;
> + *regno = sysm & 1 ? 13 : 14;
> + break;
> + case 0x14 ... 0x15: /* 0b1010x : r14_abt, r13_abt */
> + *tgtmode = ARM_CPU_MODE_ABT;
> + *regno = sysm & 1 ? 13 : 14;
> + break;
> + case 0x16 ... 0x17: /* 0b1011x : r14_und, r13_und */
> + *tgtmode = ARM_CPU_MODE_UND;
> + *regno = sysm & 1 ? 13 : 14;
> + break;
> + case 0x1c ... 0x1d: /* 0b1110x : r14_mon, r13_mon */
> + *tgtmode = ARM_CPU_MODE_MON;
> + *regno = sysm & 1 ? 13 : 14;
> + break;
> + case 0x1e ... 0x1f: /* 0b1111x : elr_hyp, r13_hyp */
> + *tgtmode = ARM_CPU_MODE_HYP;
> + /* Arbitrarily pick 17 for ELR_Hyp (which is not a banked LR!) */
> + *regno = sysm & 1 ? 13 : 17;
> + break;
> + default: /* unallocated */
> + goto undef;
> + }
> + }
> +
> + /* Catch the 'accessing inaccessible register' cases we can detect
> + * at translate time.
> + */
> + switch (*tgtmode) {
> + case ARM_CPU_MODE_MON:
> + if (!arm_dc_feature(s, ARM_FEATURE_EL3) || s->ns) {
> + goto undef;
> + }
> + if (s->current_el == 1) {
> + /* If we're in Secure EL1 (which implies that EL3 is AArch64)
> + * then accesses to Mon registers trap to EL3
> + */
> + exc_target = 3;
> + goto undef;
> + }
> + break;
> + case ARM_CPU_MODE_HYP:
> + /* Note that we can forbid accesses from EL2 here because they
> + * must be from Hyp mode itself
> + */
> + if (!arm_dc_feature(s, ARM_FEATURE_EL2) || s->current_el < 3) {
> + goto undef;
> + }
> + break;
> + default:
> + break;
> + }
> +
> + return true;
> +
> +undef:
> + /* If we get here then some access check did not pass */
> + gen_exception_insn(s, 4, EXCP_UDEF, syn_uncategorized(), exc_target);
> + return false;
> +}
> +
> +static void gen_msr_banked(DisasContext *s, int r, int sysm, int rn)
> +{
> + TCGv_i32 tcg_reg, tcg_tgtmode, tcg_regno;
> + int tgtmode, regno;
> +
> + if (!msr_banked_access_decode(s, r, sysm, rn, &tgtmode, ®no)) {
> + return;
> + }
> +
> + /* Sync state because msr_banked() can raise exceptions */
> + gen_set_condexec(s);
> + gen_set_pc_im(s, s->pc - 4);
> + tcg_reg = load_reg(s, rn);
> + tcg_tgtmode = tcg_const_i32(tgtmode);
> + tcg_regno = tcg_const_i32(regno);
> + gen_helper_msr_banked(cpu_env, tcg_reg, tcg_tgtmode, tcg_regno);
> + tcg_temp_free_i32(tcg_tgtmode);
> + tcg_temp_free_i32(tcg_regno);
> + tcg_temp_free_i32(tcg_reg);
> + s->is_jmp = DISAS_UPDATE;
> +}
> +
> +static void gen_mrs_banked(DisasContext *s, int r, int sysm, int rn)
> +{
> + TCGv_i32 tcg_reg, tcg_tgtmode, tcg_regno;
> + int tgtmode, regno;
> +
> + if (!msr_banked_access_decode(s, r, sysm, rn, &tgtmode, ®no)) {
> + return;
> + }
> +
> + /* Sync state because mrs_banked() can raise exceptions */
> + gen_set_condexec(s);
> + gen_set_pc_im(s, s->pc - 4);
> + tcg_reg = tcg_temp_new_i32();
> + tcg_tgtmode = tcg_const_i32(tgtmode);
> + tcg_regno = tcg_const_i32(regno);
> + gen_helper_mrs_banked(tcg_reg, cpu_env, tcg_tgtmode, tcg_regno);
> + tcg_temp_free_i32(tcg_tgtmode);
> + tcg_temp_free_i32(tcg_regno);
> + store_reg(s, rn, tcg_reg);
> + s->is_jmp = DISAS_UPDATE;
> +}
> +
> /* Generate an old-style exception return. Marks pc as dead. */
> static void gen_exception_return(DisasContext *s, TCGv_i32 pc)
> {
> @@ -7950,7 +8139,26 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
> sh = (insn >> 4) & 0xf;
> rm = insn & 0xf;
> switch (sh) {
> - case 0x0: /* move program status register */
> + case 0x0: /* MSR, MRS */
> + if (insn & (1 << 9)) {
> + /* MSR (banked) and MRS (banked) */
> + int sysm = extract32(insn, 16, 4) |
> + (extract32(insn, 8, 1) << 4);
> + int r = extract32(insn, 22, 1);
> +
> + if (op1 & 1) {
> + /* MSR (banked) */
> + gen_msr_banked(s, r, sysm, rm);
> + } else {
> + /* MRS (banked) */
> + int rd = extract32(insn, 12, 4);
> +
> + gen_mrs_banked(s, r, sysm, rd);
> + }
> + break;
> + }
> +
> + /* MSR, MRS (for PSRs) */
> if (op1 & 1) {
> /* PSR = reg */
> tmp = load_reg(s, rm);
> @@ -10055,6 +10263,18 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
> if (arm_dc_feature(s, ARM_FEATURE_M)) {
> goto illegal_op;
> }
> +
> + if (extract32(insn, 5, 1)) {
> + /* MSR (banked) */
> + int sysm = extract32(insn, 8, 4) |
> + (extract32(insn, 4, 1) << 4);
> + int r = op & 1;
> +
> + gen_msr_banked(s, r, sysm, rm);
> + break;
> + }
> +
> + /* MSR (for PSRs) */
> tmp = load_reg(s, rn);
> if (gen_set_psr(s,
> msr_mask(s, (insn >> 8) & 0xf, op == 1),
> @@ -10127,7 +10347,17 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
> tcg_gen_subi_i32(tmp, tmp, insn & 0xff);
> gen_exception_return(s, tmp);
> break;
> - case 6: /* mrs cpsr. */
> + case 6: /* MRS */
> + if (extract32(insn, 5, 1)) {
> + /* MRS (banked) */
> + int sysm = extract32(insn, 16, 4) |
> + (extract32(insn, 4, 1) << 4);
> +
> + gen_mrs_banked(s, 0, sysm, rd);
> + break;
> + }
> +
> + /* mrs cpsr */
> tmp = tcg_temp_new_i32();
> if (arm_dc_feature(s, ARM_FEATURE_M)) {
> addr = tcg_const_i32(insn & 0xff);
> @@ -10138,7 +10368,17 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
> }
> store_reg(s, rd, tmp);
> break;
> - case 7: /* mrs spsr. */
> + case 7: /* MRS */
> + if (extract32(insn, 5, 1)) {
> + /* MRS (banked) */
> + int sysm = extract32(insn, 16, 4) |
> + (extract32(insn, 4, 1) << 4);
> +
> + gen_mrs_banked(s, 1, sysm, rd);
> + break;
> + }
> +
> + /* mrs spsr. */
> /* Not accessible in user mode. */
> if (IS_USER(s) || arm_dc_feature(s, ARM_FEATURE_M)) {
> goto illegal_op;
> --
> 1.9.1
>
next prev parent reply other threads:[~2016-02-29 21:23 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-02-29 16:18 [Qemu-arm] [PATCH] target-arm: Implement MRS (banked) and MSR (banked) instructions Peter Maydell
2016-02-29 16:18 ` [Qemu-devel] " Peter Maydell
2016-02-29 16:24 ` [Qemu-arm] " Sergey Fedorov
2016-02-29 16:24 ` [Qemu-devel] " Sergey Fedorov
2016-02-29 16:25 ` [Qemu-arm] " Peter Maydell
2016-02-29 16:25 ` [Qemu-devel] " Peter Maydell
2016-02-29 21:22 ` Edgar E. Iglesias [this message]
2016-02-29 21:22 ` Edgar E. Iglesias
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=20160229212239.GF16305@toto \
--to=edgar.iglesias@gmail.com \
--cc=peter.maydell@linaro.org \
--cc=qemu-arm@nongnu.org \
--cc=qemu-devel@nongnu.org \
/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.