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
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~
© 2016 - 2025 Red Hat, Inc.