* [Qemu-devel] [PATCH] target-arm: Implement MRS (banked) and MSR (banked) instructions
@ 2016-02-29 16:18 Peter Maydell
2016-02-29 16:24 ` Sergey Fedorov
2016-02-29 21:22 ` Edgar E. Iglesias
0 siblings, 2 replies; 4+ messages in thread
From: Peter Maydell @ 2016-02-29 16:18 UTC (permalink / raw)
To: qemu-devel; +Cc: Edgar E. Iglesias, qemu-arm, Sergey Fedorov
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.
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
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [Qemu-devel] [PATCH] target-arm: Implement MRS (banked) and MSR (banked) instructions
2016-02-29 16:18 [Qemu-devel] [PATCH] target-arm: Implement MRS (banked) and MSR (banked) instructions Peter Maydell
@ 2016-02-29 16:24 ` Sergey Fedorov
2016-02-29 16:25 ` Peter Maydell
2016-02-29 21:22 ` Edgar E. Iglesias
1 sibling, 1 reply; 4+ messages in thread
From: Sergey Fedorov @ 2016-02-29 16:24 UTC (permalink / raw)
To: Peter Maydell, qemu-devel; +Cc: Edgar E. Iglesias, qemu-arm
On 29.02.2016 19:18, 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.
Likely, there is no disassembling support in QEMU for these instructions
as well. Are you going to add it?
Best regards,
Sergey
>
> 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...
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [Qemu-devel] [PATCH] target-arm: Implement MRS (banked) and MSR (banked) instructions
2016-02-29 16:24 ` Sergey Fedorov
@ 2016-02-29 16:25 ` Peter Maydell
0 siblings, 0 replies; 4+ messages in thread
From: Peter Maydell @ 2016-02-29 16:25 UTC (permalink / raw)
To: Sergey Fedorov; +Cc: Edgar E. Iglesias, qemu-arm, QEMU Developers
On 29 February 2016 at 16:24, Sergey Fedorov <serge.fdrv@gmail.com> wrote:
> On 29.02.2016 19:18, 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.
>
> Likely, there is no disassembling support in QEMU for these instructions
> as well. Are you going to add it?
No, I don't plan to.
thanks
-- PMM
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [Qemu-devel] [PATCH] target-arm: Implement MRS (banked) and MSR (banked) instructions
2016-02-29 16:18 [Qemu-devel] [PATCH] target-arm: Implement MRS (banked) and MSR (banked) instructions Peter Maydell
2016-02-29 16:24 ` Sergey Fedorov
@ 2016-02-29 21:22 ` Edgar E. Iglesias
1 sibling, 0 replies; 4+ messages in thread
From: Edgar E. Iglesias @ 2016-02-29 21:22 UTC (permalink / raw)
To: Peter Maydell; +Cc: Sergey Fedorov, qemu-arm, qemu-devel
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
>
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2016-02-29 21:22 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-02-29 16:18 [Qemu-devel] [PATCH] target-arm: Implement MRS (banked) and MSR (banked) instructions Peter Maydell
2016-02-29 16:24 ` Sergey Fedorov
2016-02-29 16:25 ` Peter Maydell
2016-02-29 21:22 ` Edgar E. Iglesias
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).