@@ -13,6 +13,9 @@ the following architecture extensions:
- FEAT_BF16 (AArch64 BFloat16 instructions)
- FEAT_BTI (Branch Target Identification)
- FEAT_CSV2 (Cache speculation variant 2)
+- FEAT_CSV2_1p1 (Cache speculation variant 2, version 1.1)
+- FEAT_CSV2_1p2 (Cache speculation variant 2, version 1.2)
+- FEAT_CSV2_2 (Cache speculation variant 2, version 2)
- FEAT_DIT (Data Independent Timing instructions)
- FEAT_DPB (DC CVAP instruction)
- FEAT_Debugv8p2 (Debug changes for v8.2)
@@ -688,6 +688,8 @@ typedef struct CPUArchState {
ARMPACKey apdb;
ARMPACKey apga;
} keys;
+
+ uint64_t scxtnum_el[4];
#endif
#if defined(CONFIG_USER_ONLY)
@@ -1211,6 +1213,7 @@ void pmu_init(ARMCPU *cpu);
#define SCTLR_WXN (1U << 19)
#define SCTLR_ST (1U << 20) /* up to ??, RAZ in v6 */
#define SCTLR_UWXN (1U << 20) /* v7 onward, AArch32 only */
+#define SCTLR_TSCXT (1U << 20) /* FEAT_CSV2_1p2, AArch64 only */
#define SCTLR_FI (1U << 21) /* up to v7, v8 RES0 */
#define SCTLR_IESB (1U << 21) /* v8.2-IESB, AArch64 only */
#define SCTLR_U (1U << 22) /* up to v6, RAO in v7 */
@@ -4022,6 +4025,19 @@ static inline bool isar_feature_aa64_dit(const ARMISARegisters *id)
return FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, DIT) != 0;
}
+static inline bool isar_feature_aa64_scxtnum(const ARMISARegisters *id)
+{
+ int key = FIELD_EX64(id->id_aa64pfr0, ID_AA64PFR0, CSV2);
+ if (key >= 2) {
+ return true; /* FEAT_CSV2_2 */
+ }
+ if (key == 1) {
+ key = FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, CSV2_FRAC);
+ return key >= 2; /* FEAT_CSV2_1p2 */
+ }
+ return false;
+}
+
static inline bool isar_feature_aa64_ssbs(const ARMISARegisters *id)
{
return FIELD_EX64(id->id_aa64pfr1, ID_AA64PFR1, SSBS) != 0;
@@ -230,6 +230,11 @@ static void arm_cpu_reset(DeviceState *dev)
*/
env->cp15.gcr_el1 = 0x1ffff;
}
+ /*
+ * Disable access to SCXTNUM_EL0 from CSV2_1p2.
+ * This is not yet exposed from the Linux kernel in any way.
+ */
+ env->cp15.sctlr_el[1] |= SCTLR_TSCXT;
#else
/* Reset into the highest available EL */
if (arm_feature(env, ARM_FEATURE_EL3)) {
@@ -748,7 +748,7 @@ static void aarch64_max_initfn(Object *obj)
t = FIELD_DP64(t, ID_AA64PFR0, SVE, 1);
t = FIELD_DP64(t, ID_AA64PFR0, SEL2, 1); /* FEAT_SEL2 */
t = FIELD_DP64(t, ID_AA64PFR0, DIT, 1); /* FEAT_DIT */
- t = FIELD_DP64(t, ID_AA64PFR0, CSV2, 1); /* FEAT_CSV2 */
+ t = FIELD_DP64(t, ID_AA64PFR0, CSV2, 2); /* FEAT_CSV2_2 */
cpu->isar.id_aa64pfr0 = t;
t = cpu->isar.id_aa64pfr1;
@@ -760,6 +760,7 @@ static void aarch64_max_initfn(Object *obj)
* we do for EL2 with the virtualization=on property.
*/
t = FIELD_DP64(t, ID_AA64PFR1, MTE, 3); /* FEAT_MTE3 */
+ t = FIELD_DP64(t, ID_AA64PFR1, CSV2_FRAC, 0); /* FEAT_CSV2_2 */
cpu->isar.id_aa64pfr1 = t;
t = cpu->isar.id_aa64mmfr0;
@@ -1770,6 +1770,9 @@ static void scr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
if (cpu_isar_feature(aa64_mte, cpu)) {
valid_mask |= SCR_ATA;
}
+ if (cpu_isar_feature(aa64_scxtnum, cpu)) {
+ valid_mask |= SCR_ENSCXT;
+ }
} else {
valid_mask &= ~(SCR_RW | SCR_ST);
if (cpu_isar_feature(aa32_ras, cpu)) {
@@ -5149,6 +5152,9 @@ static void do_hcr_write(CPUARMState *env, uint64_t value, uint64_t valid_mask)
if (cpu_isar_feature(aa64_mte, cpu)) {
valid_mask |= HCR_ATA | HCR_DCT | HCR_TID5;
}
+ if (cpu_isar_feature(aa64_scxtnum, cpu)) {
+ valid_mask |= HCR_ENSCXT;
+ }
}
/* Clear RES0 bits. */
@@ -5800,6 +5806,10 @@ static void define_arm_vh_e2h_redirects_aliases(ARMCPU *cpu)
{ K(3, 0, 5, 6, 0), K(3, 4, 5, 6, 0), K(3, 5, 5, 6, 0),
"TFSR_EL1", "TFSR_EL2", "TFSR_EL12", isar_feature_aa64_mte },
+ { K(3, 0, 13, 0, 7), K(3, 4, 13, 0, 7), K(3, 5, 13, 0, 7),
+ "SCXTNUM_EL1", "SCXTNUM_EL2", "SCXTNUM_EL12",
+ isar_feature_aa64_scxtnum },
+
/* TODO: ARMv8.2-SPE -- PMSCR_EL2 */
/* TODO: ARMv8.4-Trace -- TRFCR_EL2 */
};
@@ -7223,7 +7233,52 @@ static const ARMCPRegInfo mte_el0_cacheop_reginfo[] = {
},
};
-#endif
+static CPAccessResult access_scxtnum(CPUARMState *env, const ARMCPRegInfo *ri,
+ bool isread)
+{
+ uint64_t hcr = arm_hcr_el2_eff(env);
+ int el = arm_current_el(env);
+
+ if (el == 0 && !((hcr & HCR_E2H) && (hcr & HCR_TGE))) {
+ if (env->cp15.sctlr_el[1] & SCTLR_TSCXT) {
+ if (hcr & HCR_TGE) {
+ return CP_ACCESS_TRAP_EL2;
+ }
+ return CP_ACCESS_TRAP;
+ }
+ } else if (el < 2 && (env->cp15.sctlr_el[2] & SCTLR_TSCXT)) {
+ return CP_ACCESS_TRAP_EL2;
+ }
+ if (el < 2 && arm_is_el2_enabled(env) && !(hcr & HCR_ENSCXT)) {
+ return CP_ACCESS_TRAP_EL2;
+ }
+ if (el < 3
+ && arm_feature(env, ARM_FEATURE_EL3)
+ && !(env->cp15.scr_el3 & SCR_ENSCXT)) {
+ return CP_ACCESS_TRAP_EL3;
+ }
+ return CP_ACCESS_OK;
+}
+
+static const ARMCPRegInfo scxtnum_reginfo[] = {
+ { .name = "SCXTNUM_EL0", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 3, .crn = 13, .crm = 0, .opc2 = 7,
+ .access = PL0_RW, .accessfn = access_scxtnum,
+ .fieldoffset = offsetof(CPUARMState, scxtnum_el[0]) },
+ { .name = "SCXTNUM_EL1", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 0, .crn = 13, .crm = 0, .opc2 = 7,
+ .access = PL1_RW, .accessfn = access_scxtnum,
+ .fieldoffset = offsetof(CPUARMState, scxtnum_el[1]) },
+ { .name = "SCXTNUM_EL2", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 4, .crn = 13, .crm = 0, .opc2 = 7,
+ .access = PL2_RW, .accessfn = access_scxtnum,
+ .fieldoffset = offsetof(CPUARMState, scxtnum_el[2]) },
+ { .name = "SCXTNUM_EL3", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 6, .crn = 13, .crm = 0, .opc2 = 7,
+ .access = PL3_RW,
+ .fieldoffset = offsetof(CPUARMState, scxtnum_el[3]) },
+};
+#endif /* TARGET_AARCH64 */
static CPAccessResult access_predinv(CPUARMState *env, const ARMCPRegInfo *ri,
bool isread)
@@ -8365,6 +8420,10 @@ void register_cp_regs_for_features(ARMCPU *cpu)
define_arm_cp_regs(cpu, mte_tco_ro_reginfo);
define_arm_cp_regs(cpu, mte_el0_cacheop_reginfo);
}
+
+ if (cpu_isar_feature(aa64_scxtnum, cpu)) {
+ define_arm_cp_regs(cpu, scxtnum_reginfo);
+ }
#endif
if (cpu_isar_feature(any_predinv, cpu)) {