[WIP-for-10.1 v2 4/5] target/arm: Add FEAT_TCR2

Gustavo Romero posted 5 patches 5 months, 2 weeks ago
There is a newer version of this series
[WIP-for-10.1 v2 4/5] target/arm: Add FEAT_TCR2
Posted by Gustavo Romero 5 months, 2 weeks ago
Add FEAT_TCR2, which introduces TCR2_EL1 and TCR2_EL2 registers. These
registers are extensions of the TCR_ELx registers and provide top-level
control of the EL10 and EL20 translation regimes.

Since the bits in these registers depend on other CPU features, and only
FEAT_MEC is supported at the moment, the FEAT_TCR2 registers only
implement the bits related to FEAT_MEC for now.

Signed-off-by: Gustavo Romero <gustavo.romero@linaro.org>
---
 docs/system/arm/emulation.rst |  1 +
 target/arm/cpu-features.h     |  5 +++++
 target/arm/cpu.h              |  1 +
 target/arm/helper.c           | 40 +++++++++++++++++++++++++++++++++++
 target/arm/internals.h        | 18 ++++++++++++++++
 5 files changed, 65 insertions(+)

diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst
index 5a82c602f2..611d7385d8 100644
--- a/docs/system/arm/emulation.rst
+++ b/docs/system/arm/emulation.rst
@@ -143,6 +143,7 @@ the following architecture extensions:
 - FEAT_SPECRES (Speculation restriction instructions)
 - FEAT_SSBS (Speculative Store Bypass Safe)
 - FEAT_SSBS2 (MRS and MSR instructions for SSBS version 2)
+- FEAT_TCR2 (Support for TCR2_ELx)
 - FEAT_TGran16K (Support for 16KB memory translation granule size at stage 1)
 - FEAT_TGran4K (Support for 4KB memory translation granule size at stage 1)
 - FEAT_TGran64K (Support for 64KB memory translation granule size at stage 1)
diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h
index a42d1133c2..e6a731472f 100644
--- a/target/arm/cpu-features.h
+++ b/target/arm/cpu-features.h
@@ -485,6 +485,11 @@ static inline bool isar_feature_aa64_xs(const ARMISARegisters *id)
     return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, XS) != 0;
 }
 
+static inline bool isar_feature_aa64_tcr2(const ARMISARegisters *id)
+{
+    return FIELD_EX64(id->id_aa64mmfr3, ID_AA64MMFR3, TCRX) != 0;
+}
+
 /*
  * These are the values from APA/API/APA3.
  * In general these must be compared '>=', per the normal Arm ARM
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index ac38306873..6fd984a22f 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -355,6 +355,7 @@ typedef struct CPUArchState {
         uint64_t vsttbr_el2; /* Secure Virtualization Translation Table. */
         /* MMU translation table base control. */
         uint64_t tcr_el[4];
+        uint64_t tcr2_el[3];
         uint64_t vtcr_el2; /* Virtualization Translation Control.  */
         uint64_t vstcr_el2; /* Secure Virtualization Translation Control. */
         uint32_t c2_data; /* MPU data cacheable bits.  */
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 413672174b..c34aa18ee3 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -7887,6 +7887,42 @@ static const ARMCPRegInfo sctlr2_reginfo[] = {
       .fieldoffset = offsetof(CPUARMState, cp15.sctlr2_el[3]) },
 };
 
+static CPAccessResult tcr2_access(CPUARMState *env, const ARMCPRegInfo *ri,
+                                  bool isread)
+{
+    return CP_ACCESS_OK;
+};
+
+static void tcr2_write(CPUARMState *env, const ARMCPRegInfo *ri,
+                       uint64_t value)
+{
+    int el = arm_current_el(env);
+    uint64_t valid_mask = 0ULL;
+
+    valid_mask |= TCR2_AMEC0;
+    if (el_is_in_host(env, el)) {
+        if (cpu_isar_feature(aa64_mec, env_archcpu(env))) {
+            valid_mask |= TCR2_AMEC1;
+	}
+    }
+
+    value &= valid_mask;
+    raw_write(env, ri, value);
+}
+
+static const ARMCPRegInfo tcr2_reginfo[] = {
+    { .name = "TCR2_EL1", .state = ARM_CP_STATE_AA64,
+      .opc0 = 3, .opc1 = 0, .opc2 = 3, .crn = 2, .crm = 0,
+      .access = PL1_RW, .accessfn = tcr2_access,
+      .writefn = tcr2_write,
+      .fieldoffset = offsetof(CPUARMState, cp15.tcr2_el[1]) },
+    { .name = "TCR2_EL2", .state = ARM_CP_STATE_AA64,
+      .opc0 = 3, .opc1 = 4, .opc2 = 3, .crn = 2, .crm = 0,
+      .access = PL2_RW, .accessfn = tcr2_access,
+      .writefn = tcr2_write,
+      .fieldoffset = offsetof(CPUARMState, cp15.tcr2_el[2]) },
+};
+
 void register_cp_regs_for_features(ARMCPU *cpu)
 {
     /* Register all the coprocessor registers based on feature bits */
@@ -9157,6 +9193,10 @@ void register_cp_regs_for_features(ARMCPU *cpu)
         define_arm_cp_regs(cpu, sctlr2_reginfo);
     }
 
+    if (cpu_isar_feature(aa64_tcr2, cpu)) {
+        define_arm_cp_regs(cpu, tcr2_reginfo);
+    }
+
     if (cpu_isar_feature(any_predinv, cpu)) {
         define_arm_cp_regs(cpu, predinv_reginfo);
     }
diff --git a/target/arm/internals.h b/target/arm/internals.h
index 3360de9150..a4886f9406 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -201,6 +201,24 @@ FIELD(CPTR_EL3, TCPAC, 31, 1)
 #define TTBCR_SH1    (1U << 28)
 #define TTBCR_EAE    (1U << 31)
 
+#define TCR2_PNCH    (1ULL << 0)
+#define TCR2_PIE     (1ULL << 1)
+#define TCR2_E0POE   (1ULL << 2)
+#define TCR2_POE     (1ULL << 3)
+#define TCR2_AIE     (1ULL << 4)
+#define TCR2_D128    (1ULL << 5)
+#define TCR2_PTTWI   (1ULL << 10)
+#define TCR2_HAFT    (1ULL << 11)
+#define TCR2_AMEC0   (1ULL << 12)
+#define TCR2_AMEC1   (1ULL << 13)
+#define TCR2_DISCH0  (1ULL << 14)
+#define TCR2_DISCH1  (1ULL << 15)
+#define TCR2_A2      (1ULL << 16)
+#define TCR2_FNG0    (1ULL << 17)
+#define TCR2_FNG1    (1ULL << 18)
+#define TCR2_FNGNA0  (1ULL << 20)
+#define TCR2_FNGNA1  (1ULL << 21)
+
 FIELD(VTCR, T0SZ, 0, 6)
 FIELD(VTCR, SL0, 6, 2)
 FIELD(VTCR, IRGN0, 8, 2)
-- 
2.34.1
Re: [WIP-for-10.1 v2 4/5] target/arm: Add FEAT_TCR2
Posted by Richard Henderson 5 months, 2 weeks ago
On 7/4/25 09:14, Gustavo Romero wrote:
> +static CPAccessResult tcr2_access(CPUARMState *env, const ARMCPRegInfo *ri,
> +                                  bool isread)
> +{
> +    return CP_ACCESS_OK;
> +};

Eh?  This is missing everything: TRVM, HCRX_EL2.TCR2En, SCR_EL3.TCR2En.
Two different functions required for TCR2_EL1 and TCR2_EL2.

> +
> +static void tcr2_write(CPUARMState *env, const ARMCPRegInfo *ri,
> +                       uint64_t value)
> +{
> +    int el = arm_current_el(env);
> +    uint64_t valid_mask = 0ULL;
> +
> +    valid_mask |= TCR2_AMEC0;
> +    if (el_is_in_host(env, el)) {
> +        if (cpu_isar_feature(aa64_mec, env_archcpu(env))) {
> +            valid_mask |= TCR2_AMEC1;
> +	}

This is incorrect.

(1) Both bits are reserved unless FEAT_MEC.
(2) Bits that change interpretation based on el_is_in_host must always be writable, but 
ignored when !el_is_in_host.

> +    }
> +
> +    value &= valid_mask;
> +    raw_write(env, ri, value);
> +}
> +
> +static const ARMCPRegInfo tcr2_reginfo[] = {
> +    { .name = "TCR2_EL1", .state = ARM_CP_STATE_AA64,
> +      .opc0 = 3, .opc1 = 0, .opc2 = 3, .crn = 2, .crm = 0,
> +      .access = PL1_RW, .accessfn = tcr2_access,
> +      .writefn = tcr2_write,
> +      .fieldoffset = offsetof(CPUARMState, cp15.tcr2_el[1]) },

Missing FGT and NV2 settings.


r~