The algorithm used for hashing is a simple XOR between the pointer and the modifier using the "implementation defined" scheme.
Signed-off-by: Torbjörn SVENSSON <[email protected]> --- target/arm/cpu-features.h | 6 +++ target/arm/internals.h | 2 + target/arm/tcg/cpu-v7m.c | 2 +- target/arm/tcg/m_helper.c | 17 ++++++++ target/arm/tcg/translate.c | 98 ++++++++++++++++++++++++++++++++++++++++------ 5 files changed, 113 insertions(+), 12 deletions(-) diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h index 4e44245a8b..60bd7a0765 100644 --- a/target/arm/cpu-features.h +++ b/target/arm/cpu-features.h @@ -114,6 +114,7 @@ FIELD(ID_ISAR5, AES, 4, 4) FIELD(ID_ISAR5, SHA1, 8, 4) FIELD(ID_ISAR5, SHA2, 12, 4) FIELD(ID_ISAR5, CRC32, 16, 4) +FIELD(ID_ISAR5, PACBTI, 20, 4) FIELD(ID_ISAR5, RDM, 24, 4) FIELD(ID_ISAR5, VCMA, 28, 4) @@ -583,6 +584,11 @@ static inline bool isar_feature_aa32_m_sec_state(const ARMISARegisters *id) return FIELD_EX32_IDREG(id, ID_PFR1, SECURITY) >= 3; } +static inline bool isar_feature_aa32_m_pacbti(const ARMISARegisters *id) +{ + return FIELD_EX32_IDREG(id, ID_ISAR5, PACBTI) != 0; +} + static inline bool isar_feature_aa32_fp16_arith(const ARMISARegisters *id) { /* Sadly this is encoded differently for A-profile and M-profile */ diff --git a/target/arm/internals.h b/target/arm/internals.h index 00830b1724..cbb0a1d8fc 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -90,6 +90,8 @@ FIELD(V7M_CONTROL, NPRIV, 0, 1) FIELD(V7M_CONTROL, SPSEL, 1, 1) FIELD(V7M_CONTROL, FPCA, 2, 1) FIELD(V7M_CONTROL, SFPA, 3, 1) +FIELD(V7M_CONTROL, PAC_EN, 6, 1) +FIELD(V7M_CONTROL, UPAC_EN, 7, 1) /* Bit definitions for v7M exception return payload */ FIELD(V7M_EXCRET, ES, 0, 1) diff --git a/target/arm/tcg/cpu-v7m.c b/target/arm/tcg/cpu-v7m.c index 5cfda232cd..3beb2b23fa 100644 --- a/target/arm/tcg/cpu-v7m.c +++ b/target/arm/tcg/cpu-v7m.c @@ -269,7 +269,7 @@ static void cortex_m85_initfn(Object *obj) SET_IDREG(isar, ID_ISAR2, 0x20232232); SET_IDREG(isar, ID_ISAR3, 0x01111131); SET_IDREG(isar, ID_ISAR4, 0x01310132); - SET_IDREG(isar, ID_ISAR5, 0x00000000); + SET_IDREG(isar, ID_ISAR5, 0x00200000); /* PACBTI=implementation defined */ SET_IDREG(isar, ID_ISAR6, 0x00000000); SET_IDREG(isar, CLIDR, 0x00000000); /* caches not implemented */ cpu->ctr = 0x8303c003; diff --git a/target/arm/tcg/m_helper.c b/target/arm/tcg/m_helper.c index f2059ed8b0..1160fe8d87 100644 --- a/target/arm/tcg/m_helper.c +++ b/target/arm/tcg/m_helper.c @@ -2658,6 +2658,15 @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val) env->v7m.control[M_REG_S] &= ~R_V7M_CONTROL_FPCA_MASK; env->v7m.control[M_REG_S] |= val & R_V7M_CONTROL_FPCA_MASK; } + + /* Only update PAC_EN / UPAC_EN if PACBTI is implemented. */ + if (cpu_isar_feature(aa32_m_pacbti, env_archcpu(env))) { + uint32_t enable_mask = + R_V7M_CONTROL_PAC_EN_MASK | R_V7M_CONTROL_UPAC_EN_MASK; + env->v7m.control[M_REG_NS] &= ~enable_mask; + env->v7m.control[M_REG_NS] |= val & enable_mask; + } + return; case 0x98: /* SP_NS */ { @@ -2784,6 +2793,14 @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val) env->v7m.control[M_REG_S] |= val & R_V7M_CONTROL_FPCA_MASK; } } + + /* Only update PAC_EN / UPAC_EN if PACBTI is implemented. */ + if (cpu_isar_feature(aa32_m_pacbti, env_archcpu(env))) { + uint32_t enable_mask = + R_V7M_CONTROL_PAC_EN_MASK | R_V7M_CONTROL_UPAC_EN_MASK; + env->v7m.control[env->v7m.secure] &= ~enable_mask; + env->v7m.control[env->v7m.secure] |= val & enable_mask; + } break; default: bad_reg: diff --git a/target/arm/tcg/translate.c b/target/arm/tcg/translate.c index ae1351ef03..e13119b33b 100644 --- a/target/arm/tcg/translate.c +++ b/target/arm/tcg/translate.c @@ -5012,26 +5012,80 @@ static bool trans_SMMLSR(DisasContext *s, arg_rrrr *a) return op_smmla(s, a, true, true); } +static void arm_gen_test_pac_enabled(DisasContext *s, TCGLabel *label) +{ + int bank = s->v8m_secure ? M_REG_S : M_REG_NS; + int mask = IS_USER(s) + ? R_V7M_CONTROL_UPAC_EN_MASK + : R_V7M_CONTROL_PAC_EN_MASK; + TCGv_i32 temp = load_cpu_field(v7m.control[bank]); + tcg_gen_brcondi_i32(TCG_COND_TSTEQ, temp, mask, label); +} + +static TCGv_i32 op_create_pac_hash(DisasContext *s, int rn, int rm) +{ + TCGv_i32 res = tcg_temp_new_i32(); + TCGv_i64 ext_ptr = tcg_temp_new_i64(); + TCGv_i64 modifier = tcg_temp_new_i64(); + TCGv_i64 temp = tcg_temp_new_i64(); + + tcg_gen_extu_i32_i64(ext_ptr, load_reg(s, rn)); + tcg_gen_extu_i32_i64(modifier, load_reg(s, rm)); + + /* + * This a very simple implementation that just xor the two + * inputs. The goal is not to replicate any of the predefined + * hashing functions, but use a simple check. + */ + tcg_gen_xor_i64(temp, ext_ptr, modifier); + + /* Return the lower word */ + tcg_gen_extrl_i64_i32(res, temp); + return res; +} + +static bool op_pacg(DisasContext *s, arg_rrr *a) +{ + TCGv_i32 temp; + TCGLabel *done = gen_new_label(); + + arm_gen_test_pac_enabled(s, done); + + temp = op_create_pac_hash(s, a->rn, a->rm); + store_reg(s, a->rd, temp); + + gen_set_label(done); + return true; +} + static bool trans_PAC(DisasContext *s, arg_empty *a) { + arg_rrr arg; + if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) { return false; } - /* Handle as if PACBTI is disabled. */ - return true; + arg.rd = 0xc; /* R12 */ + arg.rn = 0xe; /* LR */ + arg.rm = 0xd; /* SP */ + return op_pacg(s, &arg); } static bool trans_PACBTI(DisasContext *s, arg_empty *a) { + arg_rrr arg; + if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) { return false; } /* todo: reset EPSR.B to 0 */ - /* Handle as if PACBTI is disabled. */ - return true; + arg.rd = 0xc; /* R12 */ + arg.rn = 0xe; /* LR */ + arg.rm = 0xd; /* SP */ + return op_pacg(s, &arg); } static bool trans_PACG(DisasContext *s, arg_rrr *a) @@ -5040,7 +5094,26 @@ static bool trans_PACG(DisasContext *s, arg_rrr *a) return false; } - /* Handle as if PACBTI is disabled. */ + return op_pacg(s, a); +} + +static bool op_autg(DisasContext *s, arg_rrrr *a, int set_pc_from_reg) +{ + TCGv_i32 expected_pac_hash, actual_pac_hash; + TCGLabel *done = gen_new_label(); + TCGLabel *fail = delay_exception(s, EXCP_INVSTATE, syn_uncategorized()); + + arm_gen_test_pac_enabled(s, done); + + expected_pac_hash = load_reg(s, a->ra); + actual_pac_hash = op_create_pac_hash(s, a->rn, a->rm); + tcg_gen_brcond_i32(TCG_COND_NE, expected_pac_hash, actual_pac_hash, fail); + + gen_set_label(done); + if (set_pc_from_reg >= 0) { + gen_bx_excret(s, load_reg(s, set_pc_from_reg)); + } + return true; } @@ -5050,18 +5123,22 @@ static bool trans_BXAUT(DisasContext *s, arg_rrrr *a) return false; } - /* Handle as if PACBTI is disabled. */ - return true; + return op_autg(s, a, a->rn); } static bool trans_AUT(DisasContext *s, arg_empty *a) { + arg_rrrr arg; + if (!arm_dc_feature(s, ARM_FEATURE_V8_1M)) { return false; } - /* Handle as if PACBTI is disabled. */ - return true; + arg.rd = 0; /* unused */ + arg.ra = 0xc; /* R12 */ + arg.rn = 0xe; /* LR */ + arg.rm = 0xd; /* SP */ + return op_autg(s, &arg, -1); } static bool trans_AUTG(DisasContext *s, arg_rrrr *a) @@ -5070,8 +5147,7 @@ static bool trans_AUTG(DisasContext *s, arg_rrrr *a) return false; } - /* Handle as if PACBTI is disabled. */ - return true; + return op_autg(s, a, -1); } static bool op_div(DisasContext *s, arg_rrr *a, bool u) -- 2.43.0
