[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH 2/5] target/arm: MTE user mode disassembly
From: |
Rémi Denis-Courmont |
Subject: |
[PATCH 2/5] target/arm: MTE user mode disassembly |
Date: |
Fri, 13 Mar 2020 16:00:20 +0200 |
From: Rémi Denis-Courmont <address@hidden>
This adds TCG disassembler support for the EL0-accessible instructions
from ARMv8.5-MemTag, and sets corresponding feature bit in the
"maximum" emulated CPU.
Signed-off-by: Rémi Denis-Courmont <address@hidden>
---
target/arm/cpu64.c | 7 ++
target/arm/helper.c | 30 +++++
target/arm/translate-a64.c | 236 +++++++++++++++++++++++++++++++++++--
3 files changed, 266 insertions(+), 7 deletions(-)
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index 62d36f9e8d..a72dfd3d98 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -665,6 +665,13 @@ static void aarch64_max_initfn(Object *obj)
t = cpu->isar.id_aa64pfr1;
t = FIELD_DP64(t, ID_AA64PFR1, BT, 1);
+#ifdef CONFIG_USER_ONLY
+ /* All MTE instructions and processor states are supported for user
+ * mode. This corresponds to feature field value 1 (field value 2
+ * implies MemTag memory support).
+ */
+ t = FIELD_DP64(t, ID_AA64PFR1, MTE, 1);
+#endif
cpu->isar.id_aa64pfr1 = t;
t = cpu->isar.id_aa64mmfr1;
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 38500e4f92..ed56198623 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -6839,6 +6839,33 @@ static const ARMCPRegInfo dcpodp_reg[] = {
};
#endif /*CONFIG_USER_ONLY*/
+static uint64_t tco_read(CPUARMState *env, const ARMCPRegInfo *ri)
+{
+ return env->pstate & PSTATE_TCO;
+}
+
+static void tco_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t val)
+{
+ if (val & PSTATE_TCO) {
+ env->pstate |= PSTATE_TCO;
+ } else {
+ env->pstate &= ~PSTATE_TCO;
+ }
+}
+
+static const ARMCPRegInfo mte_reginfo[] = {
+ { .name = "DC_GVA", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 4, .opc2 = 3,
+ .access = PL0_W, .type = ARM_CP_NOP },
+ { .name = "DC_GZVA", .state = ARM_CP_STATE_AA64,
+ .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 4, .opc2 = 4,
+ .access = PL0_W, .type = ARM_CP_DC_ZVA },
+ { .name = "TCO", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 3, .crn = 4, .crm = 2, .opc2 = 7,
+ .access = PL0_RW, .type = ARM_CP_NO_RAW,
+ .readfn = tco_read, .writefn = tco_write },
+ REGINFO_SENTINEL
+};
#endif
static CPAccessResult access_predinv(CPUARMState *env, const ARMCPRegInfo *ri,
@@ -7956,6 +7983,9 @@ void register_cp_regs_for_features(ARMCPU *cpu)
}
}
#endif /*CONFIG_USER_ONLY*/
+ if (cpu_isar_feature(aa64_mte, cpu)) {
+ define_arm_cp_regs(cpu, mte_reginfo);
+ }
#endif
if (cpu_isar_feature(any_predinv, cpu)) {
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
index 8fffb52203..6d86480043 100644
--- a/target/arm/translate-a64.c
+++ b/target/arm/translate-a64.c
@@ -830,6 +830,31 @@ static void gen_adc_CC(int sf, TCGv_i64 dest, TCGv_i64 t0,
TCGv_i64 t1)
}
}
+/* Extract an Allocation Tag from an address */
+static void gen_extract_tag(TCGv_i64 dest, TCGv_i64 source)
+{
+ TCGv_i64 sign = tcg_temp_new_i64();
+
+ /* See ARMv8.5-A AllocationTagFromAddress pseudocode */
+ tcg_gen_extract_i64(sign, source, 55, 1);
+ tcg_gen_extract_i64(dest, source, 56, 4);
+ tcg_gen_add_i64(dest, dest, sign);
+ tcg_gen_andi_i64(dest, dest, 0xf);
+ tcg_temp_free_i64(sign);
+}
+
+/* Deposit an Allocation Tag into an address */
+static void gen_deposit_tag(TCGv_i64 dest, TCGv_i64 source, TCGv_i64 tag)
+{
+ TCGv_i64 tmp = tcg_temp_new_i64();
+
+ /* See ARMv8.5-A AddressWithAllocationTag pseudocode */
+ tcg_gen_extract_i64(tmp, source, 55, 1);
+ tcg_gen_sub_i64(tmp, tag, tmp);
+ tcg_gen_deposit_i64(dest, source, tmp, 56, 4);
+ tcg_temp_free_i64(tmp);
+}
+
/*
* Load/Store generators
*/
@@ -1650,6 +1675,19 @@ static void handle_msr_i(DisasContext *s, uint32_t insn,
tcg_temp_free_i32(t1);
break;
+ case 0x1c: /* TCO */
+ if (!dc_isar_feature(aa64_mte, s)) {
+ unallocated_encoding(s);
+ return;
+ }
+ if (crm & 1) {
+ set_pstate_bits(PSTATE_TCO);
+ } else {
+ clear_pstate_bits(PSTATE_TCO);
+ }
+ s->base.is_jmp = DISAS_NEXT;
+ break;
+
case 0x1e: /* DAIFSet */
t1 = tcg_const_i32(crm);
gen_helper_msr_i_daifset(cpu_env, t1);
@@ -2678,6 +2716,82 @@ static void disas_ld_lit(DisasContext *s, uint32_t insn)
tcg_temp_free_i64(clean_addr);
}
+/* LDG, LDGV(EL1), ST(Z)(2)G, STGV */
+static void disas_ldst_memtag(DisasContext *s, uint32_t insn)
+{
+ int opc = extract32(insn, 22, 2);
+ int op2 = extract32(insn, 10, 2);
+ bool tuple = opc & 2;
+ bool zero_data = opc & 1;
+ bool is_store = op2 != 0;
+ bool postindex = op2 == 1;
+ bool wback = op2 != 2;
+ uint64_t offset = sextract64(insn, 12, 9) << ARM_LOG2_TAG_GRANULE;
+ int rn = extract32(insn, 5, 5);
+ int rt = extract32(insn, 0, 5);
+ TCGv_i64 tcg_addr;
+
+ if (!dc_isar_feature(aa64_mte, s) || extract32(insn, 30, 2) != 3) {
+ unallocated_encoding(s);
+ return;
+ }
+
+ if (op2 == 0 && opc != 1) {
+ unallocated_encoding(s);
+ return;
+ }
+
+ if (rn == 31) {
+ gen_check_sp_alignment(s);
+ }
+
+ tcg_addr = read_cpu_reg_sp(s, rn, 1);
+
+ if (!postindex) {
+ tcg_gen_addi_i64(tcg_addr, tcg_addr, offset);
+ }
+
+ if (is_store) {
+ /* Store Allocation Tag (STG, ST2G, STZG, STZ2G) */
+ if (zero_data) {
+ TCGv_i64 ptr = tcg_temp_new_i64();
+ TCGv_i64 zero = tcg_const_i64(0);
+
+ do_gpr_st(s, zero, tcg_addr, 3, false, 0, false, false);
+ tcg_gen_addi_i64(ptr, tcg_addr, 8);
+ do_gpr_st(s, zero, ptr, 3, false, 0, false, false);
+
+ if (tuple) {
+ tcg_gen_addi_i64(ptr, ptr, 8);
+ do_gpr_st(s, zero, ptr, 3, false, 0, false, false);
+ tcg_gen_addi_i64(ptr, ptr, 8);
+ do_gpr_st(s, zero, ptr, 3, false, 0, false, false);
+ }
+
+ tcg_temp_free_i64(zero);
+ tcg_temp_free_i64(ptr);
+ }
+ /* Write access permission should be checked here.
+ * If zero_data is true, do_gpr_st() does it but elsewise not.
+ */
+
+ if (wback) {
+ if (postindex) {
+ tcg_gen_addi_i64(tcg_addr, tcg_addr, offset);
+ }
+ tcg_gen_mov_i64(cpu_reg_sp(s, rn), tcg_addr);
+ }
+ } else {
+ /* Load Allocation Tag (LDG) */
+ TCGv_i64 tcg_tag = tcg_const_i64(0);
+
+ tcg_gen_andi_i64(tcg_addr, tcg_addr, ~(ARM_TAG_GRANULE - 1));
+ /* In principles, read access permission should be checked here. */
+ gen_deposit_tag(cpu_reg(s, rt), tcg_addr, tcg_tag);
+ tcg_temp_free_i64(tcg_tag);
+ }
+}
+
/*
* LDNP (Load Pair - non-temporal hint)
* LDP (Load Pair - non vector)
@@ -2688,6 +2802,7 @@ static void disas_ld_lit(DisasContext *s, uint32_t insn)
* LDP (Load Pair of SIMD&FP)
* STNP (Store Pair of SIMD&FP - non-temporal hint)
* STP (Store Pair of SIMD&FP)
+ * STGP (Store Pair - allocate tag)
*
* 31 30 29 27 26 25 24 23 22 21 15 14 10 9 5 4 0
* +-----+-------+---+---+-------+---+-----------------------------+
@@ -2736,8 +2851,12 @@ static void disas_ldst_pair(DisasContext *s, uint32_t
insn)
size = 2 + extract32(opc, 1, 1);
is_signed = extract32(opc, 0, 1);
if (!is_load && is_signed) {
- unallocated_encoding(s);
- return;
+ if (size == 3 || !dc_isar_feature(aa64_mte, s)) {
+ unallocated_encoding(s);
+ return;
+ }
+
+ size = 3; /* sic! */
}
}
@@ -3728,12 +3847,15 @@ static void disas_ldst(DisasContext *s, uint32_t insn)
disas_ldst_single_struct(s, insn);
break;
case 0x19: /* LDAPR/STLR (unscaled immediate) */
- if (extract32(insn, 10, 2) != 0 ||
- extract32(insn, 21, 1) != 0) {
+ if (extract32(insn, 10, 2) != 0) {
unallocated_encoding(s);
break;
}
- disas_ldst_ldapr_stlr(s, insn);
+ if (extract32(insn, 21, 1) != 0) {
+ disas_ldst_memtag(s, insn);
+ } else {
+ disas_ldst_ldapr_stlr(s, insn);
+ }
break;
default:
unallocated_encoding(s);
@@ -3791,10 +3913,12 @@ static void disas_add_sub_imm(DisasContext *s, uint32_t
insn)
bool setflags = extract32(insn, 29, 1);
bool sub_op = extract32(insn, 30, 1);
bool is_64bit = extract32(insn, 31, 1);
+ bool memtag = false;
TCGv_i64 tcg_rn = cpu_reg_sp(s, rn);
TCGv_i64 tcg_rd = setflags ? cpu_reg(s, rd) : cpu_reg_sp(s, rd);
TCGv_i64 tcg_result;
+ TCGv_i64 tcg_rtag;
switch (shift) {
case 0x0:
@@ -3802,11 +3926,23 @@ static void disas_add_sub_imm(DisasContext *s, uint32_t
insn)
case 0x1:
imm <<= 12;
break;
+ case 0x2:
+ memtag = true;
+
+ if (dc_isar_feature(aa64_mte, s) && is_64bit && !setflags) {
+ imm = extract32(imm, 6, 6) << ARM_LOG2_TAG_GRANULE;
+ break;
+ }
+ /* fall through */
default:
unallocated_encoding(s);
return;
}
+ if (memtag) {
+ tcg_rtag = tcg_const_i64(0);
+ }
+
tcg_result = tcg_temp_new_i64();
if (!setflags) {
if (sub_op) {
@@ -3824,6 +3960,11 @@ static void disas_add_sub_imm(DisasContext *s, uint32_t
insn)
tcg_temp_free_i64(tcg_imm);
}
+ if (memtag) {
+ gen_deposit_tag(tcg_result, tcg_result, tcg_rtag);
+ tcg_temp_free_i64(tcg_rtag);
+ }
+
if (is_64bit) {
tcg_gen_mov_i64(tcg_rd, tcg_result);
} else {
@@ -5281,6 +5422,72 @@ static void handle_crc32(DisasContext *s,
tcg_temp_free_i32(tcg_bytes);
}
+/* SUBP, SUBPS (incl. CCMP) */
+static void handle_subp(DisasContext *s, bool setflags, unsigned int sf,
+ unsigned int rm, unsigned int rn, unsigned int rd)
+{
+ TCGv_i64 tcg_addr1, tcg_addr2;
+ TCGv_i64 tcg_result;
+
+ if (!sf || !dc_isar_feature(aa64_mte, s)) {
+ unallocated_encoding(s);
+ return;
+ }
+
+ tcg_addr1 = tcg_temp_new_i64();
+ tcg_addr2 = tcg_temp_new_i64();
+ tcg_result = cpu_reg(s, rd);
+
+ tcg_gen_sextract_i64(tcg_addr1, cpu_reg_sp(s, rn), 0, 56);
+ tcg_gen_sextract_i64(tcg_addr2, cpu_reg_sp(s, rm), 0, 56);
+
+ if (setflags) {
+ gen_sub_CC(1, tcg_result, tcg_addr1, tcg_addr2);
+ } else {
+ tcg_gen_sub_i64(tcg_result, tcg_addr1, tcg_addr2);
+ }
+
+ tcg_temp_free_i64(tcg_addr2);
+ tcg_temp_free_i64(tcg_addr1);
+}
+
+static void handle_irg(DisasContext *s, unsigned int sf,
+ unsigned int rm, unsigned int rn, unsigned int rd)
+{
+ TCGv_i64 rtag;
+
+ if (!sf || !dc_isar_feature(aa64_mte, s)) {
+ unallocated_encoding(s);
+ return;
+ }
+
+ rtag = tcg_temp_new_i64();
+ tcg_gen_movi_i64(rtag, 0);
+ gen_deposit_tag(cpu_reg_sp(s, rd), cpu_reg_sp(s, rn), rtag);
+ tcg_temp_free_i64(rtag);
+}
+
+static void handle_gmi(DisasContext *s, unsigned int sf,
+ unsigned int rm, unsigned int rn, unsigned int rd)
+{
+ TCGv_i64 tcg_one, tcg_tag;
+
+ if (!sf || !dc_isar_feature(aa64_mte, s)) {
+ unallocated_encoding(s);
+ return;
+ }
+
+ tcg_one = tcg_const_i64(1);
+ tcg_tag = tcg_temp_new_i64();
+
+ gen_extract_tag(tcg_tag, cpu_reg_sp(s, rn));
+ tcg_gen_shl_i64(tcg_tag, tcg_one, tcg_tag);
+ tcg_gen_or_i64(cpu_reg(s, rd), cpu_reg(s, rm), tcg_tag);
+
+ tcg_temp_free_i64(tcg_tag);
+ tcg_temp_free_i64(tcg_one);
+}
+
/* Data-processing (2 source)
* 31 30 29 28 21 20 16 15 10 9 5 4 0
* +----+---+---+-----------------+------+--------+------+------+
@@ -5297,17 +5504,32 @@ static void disas_data_proc_2src(DisasContext *s,
uint32_t insn)
rd = extract32(insn, 0, 5);
if (extract32(insn, 29, 1)) {
- unallocated_encoding(s);
- return;
+ switch (opcode) {
+ case 0:
+ handle_subp(s, true, sf, rm, rn, rd);
+ break;
+ default:
+ unallocated_encoding(s);
+ return;
+ }
}
switch (opcode) {
+ case 0:
+ handle_subp(s, false, sf, rm, rn, rd);
+ break;
case 2: /* UDIV */
handle_div(s, false, sf, rm, rn, rd);
break;
case 3: /* SDIV */
handle_div(s, true, sf, rm, rn, rd);
break;
+ case 4:
+ handle_irg(s, sf, rm, rn, rd);
+ break;
+ case 5:
+ handle_gmi(s, sf, rm, rn, rd);
+ break;
case 8: /* LSLV */
handle_shift_reg(s, A64_SHIFT_TYPE_LSL, sf, rm, rn, rd);
break;
--
2.25.1
- [PATCH 2/5] target/arm: MTE user mode disassembly,
Rémi Denis-Courmont <=