aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2020-08-03 12:18:45 +0100
committerPeter Maydell <peter.maydell@linaro.org>2020-08-24 10:02:07 +0100
commitcd8be50e58f63413c033531d3273c0e44851684f (patch)
treee538b44473cccb742ec629438e88c4fbd5cb2607
parent19c23a9baafc91dd3881a7a4e9bf454e42d24e4e (diff)
target/arm: Convert A32 coprocessor insns to decodetree
Convert the A32 coprocessor instructions to decodetree. Note that this corrects an underdecoding: for the 64-bit access case (MRRC/MCRR) we did not check that bits [24:21] were 0b0010, so we would incorrectly treat LDC/STC as MRRC/MCRR rather than UNDEFing them. The decodetree versions of these insns assume the coprocessor is in the range 0..7 or 14..15. This is architecturally sensible (as per the comments) and OK in practice for QEMU because the only uses of the ARMCPRegInfo infrastructure we have that aren't for coprocessors 14 or 15 are the pxa2xx use of coprocessor 6. We add an assertion to the define_one_arm_cp_reg_with_opaque() function to catch any accidental future attempts to use it to define coprocessor registers for invalid coprocessors. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20200803111849.13368-4-peter.maydell@linaro.org
-rw-r--r--target/arm/a32.decode19
-rw-r--r--target/arm/helper.c29
-rw-r--r--target/arm/translate.c74
3 files changed, 111 insertions, 11 deletions
diff --git a/target/arm/a32.decode b/target/arm/a32.decode
index 0bd952c069..4dfd9139bf 100644
--- a/target/arm/a32.decode
+++ b/target/arm/a32.decode
@@ -47,6 +47,8 @@
&bfi rd rn lsb msb
&sat rd rn satimm imm sh
&pkh rd rn rm imm tb
+&mcr cp opc1 crn crm opc2 rt
+&mcrr cp opc1 crm rt rt2
# Data-processing (register)
@@ -529,6 +531,23 @@ LDM_a32 ---- 100 b:1 i:1 u:1 w:1 1 rn:4 list:16 &ldst_block
B .... 1010 ........................ @branch
BL .... 1011 ........................ @branch
+# Coprocessor instructions
+
+# We decode MCR, MCR, MRRC and MCRR only, because for QEMU the
+# other coprocessor instructions always UNDEF.
+# The trans_ functions for these will ignore cp values 8..13 for v7 or
+# earlier, and 0..13 for v8 and later, because those areas of the
+# encoding space may be used for other things, such as VFP or Neon.
+
+@mcr ---- .... opc1:3 . crn:4 rt:4 cp:4 opc2:3 . crm:4 &mcr
+@mcrr ---- .... .... rt2:4 rt:4 cp:4 opc1:4 crm:4 &mcrr
+
+MCRR .... 1100 0100 .... .... .... .... .... @mcrr
+MRRC .... 1100 0101 .... .... .... .... .... @mcrr
+
+MCR .... 1110 ... 0 .... .... .... ... 1 .... @mcr
+MRC .... 1110 ... 1 .... .... .... ... 1 .... @mcr
+
# Supervisor call
SVC ---- 1111 imm:24 &i
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 455c92b891..6b4f0eb533 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -8462,6 +8462,35 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu,
assert((r->state != ARM_CP_STATE_AA32) || (r->opc0 == 0));
/* AArch64 regs are all 64 bit so ARM_CP_64BIT is meaningless */
assert((r->state != ARM_CP_STATE_AA64) || !(r->type & ARM_CP_64BIT));
+ /*
+ * This API is only for Arm's system coprocessors (14 and 15) or
+ * (M-profile or v7A-and-earlier only) for implementation defined
+ * coprocessors in the range 0..7. Our decode assumes this, since
+ * 8..13 can be used for other insns including VFP and Neon. See
+ * valid_cp() in translate.c. Assert here that we haven't tried
+ * to use an invalid coprocessor number.
+ */
+ switch (r->state) {
+ case ARM_CP_STATE_BOTH:
+ /* 0 has a special meaning, but otherwise the same rules as AA32. */
+ if (r->cp == 0) {
+ break;
+ }
+ /* fall through */
+ case ARM_CP_STATE_AA32:
+ if (arm_feature(&cpu->env, ARM_FEATURE_V8) &&
+ !arm_feature(&cpu->env, ARM_FEATURE_M)) {
+ assert(r->cp >= 14 && r->cp <= 15);
+ } else {
+ assert(r->cp < 8 || (r->cp >= 14 && r->cp <= 15));
+ }
+ break;
+ case ARM_CP_STATE_AA64:
+ assert(r->cp == 0 || r->cp == CP_REG_ARM64_SYSREG_CP);
+ break;
+ default:
+ g_assert_not_reached();
+ }
/* The AArch64 pseudocode CheckSystemAccess() specifies that op1
* encodes a minimum access level for the register. We roll this
* runtime check into our general permission check code, so check
diff --git a/target/arm/translate.c b/target/arm/translate.c
index 01591f0e32..6ee920eec5 100644
--- a/target/arm/translate.c
+++ b/target/arm/translate.c
@@ -5237,6 +5237,68 @@ static int t16_pop_list(DisasContext *s, int x)
#include "decode-t32.c.inc"
#include "decode-t16.c.inc"
+static bool valid_cp(DisasContext *s, int cp)
+{
+ /*
+ * Return true if this coprocessor field indicates something
+ * that's really a possible coprocessor.
+ * For v7 and earlier, coprocessors 8..15 were reserved for Arm use,
+ * and of those only cp14 and cp15 were used for registers.
+ * cp10 and cp11 were used for VFP and Neon, whose decode is
+ * dealt with elsewhere. With the advent of fp16, cp9 is also
+ * now part of VFP.
+ * For v8A and later, the encoding has been tightened so that
+ * only cp14 and cp15 are valid, and other values aren't considered
+ * to be in the coprocessor-instruction space at all. v8M still
+ * permits coprocessors 0..7.
+ */
+ if (arm_dc_feature(s, ARM_FEATURE_V8) &&
+ !arm_dc_feature(s, ARM_FEATURE_M)) {
+ return cp >= 14;
+ }
+ return cp < 8 || cp >= 14;
+}
+
+static bool trans_MCR(DisasContext *s, arg_MCR *a)
+{
+ if (!valid_cp(s, a->cp)) {
+ return false;
+ }
+ do_coproc_insn(s, a->cp, false, a->opc1, a->crn, a->crm, a->opc2,
+ false, a->rt, 0);
+ return true;
+}
+
+static bool trans_MRC(DisasContext *s, arg_MRC *a)
+{
+ if (!valid_cp(s, a->cp)) {
+ return false;
+ }
+ do_coproc_insn(s, a->cp, false, a->opc1, a->crn, a->crm, a->opc2,
+ true, a->rt, 0);
+ return true;
+}
+
+static bool trans_MCRR(DisasContext *s, arg_MCRR *a)
+{
+ if (!valid_cp(s, a->cp)) {
+ return false;
+ }
+ do_coproc_insn(s, a->cp, true, a->opc1, 0, a->crm, 0,
+ false, a->rt, a->rt2);
+ return true;
+}
+
+static bool trans_MRRC(DisasContext *s, arg_MRRC *a)
+{
+ if (!valid_cp(s, a->cp)) {
+ return false;
+ }
+ do_coproc_insn(s, a->cp, true, a->opc1, 0, a->crm, 0,
+ true, a->rt, a->rt2);
+ return true;
+}
+
/* Helpers to swap operands for reverse-subtract. */
static void gen_rsb(TCGv_i32 dst, TCGv_i32 a, TCGv_i32 b)
{
@@ -8293,17 +8355,7 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
disas_xscale_insn(s, insn);
break;
}
-
- if ((cpnum & 0xe) == 10) {
- /* VFP, but failed disas_vfp. */
- goto illegal_op;
- }
-
- if (disas_coproc_insn(s, insn)) {
- /* Coprocessor. */
- goto illegal_op;
- }
- break;
+ /* fall through */
}
default:
illegal_op: