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


Reply via email to