target/arm: Define CNTPCTSS_EL0 and CNTVCTSS_EL0

For FEAT_ECV, new registers CNTPCTSS_EL0 and CNTVCTSS_EL0 are
defined, which are "self-synchronized" views of the physical and
virtual counts as seen in the CNTPCT_EL0 and CNTVCT_EL0 registers
(meaning that no barriers are needed around accesses to them to
ensure that reads of them do not occur speculatively and out-of-order
with other instructions).

For QEMU, all our system registers are self-synchronized, so we can
simply copy the existing implementation of CNTPCT_EL0 and CNTVCT_EL0
to the new register encodings.

This means we now implement all the functionality required for
ID_AA64MMFR0_EL1.ECV == 0b0001.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20240301183219.2424889-7-peter.maydell@linaro.org
This commit is contained in:
Peter Maydell 2024-03-07 12:19:03 +00:00
parent dcdad2624b
commit 485eb324e3

View File

@ -3389,6 +3389,34 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
},
};
/*
* FEAT_ECV adds extra views of CNTVCT_EL0 and CNTPCT_EL0 which
* are "self-synchronizing". For QEMU all sysregs are self-synchronizing,
* so our implementations here are identical to the normal registers.
*/
static const ARMCPRegInfo gen_timer_ecv_cp_reginfo[] = {
{ .name = "CNTVCTSS", .cp = 15, .crm = 14, .opc1 = 9,
.access = PL0_R, .type = ARM_CP_64BIT | ARM_CP_NO_RAW | ARM_CP_IO,
.accessfn = gt_vct_access,
.readfn = gt_virt_cnt_read, .resetfn = arm_cp_reset_ignore,
},
{ .name = "CNTVCTSS_EL0", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 3, .crn = 14, .crm = 0, .opc2 = 6,
.access = PL0_R, .type = ARM_CP_NO_RAW | ARM_CP_IO,
.accessfn = gt_vct_access, .readfn = gt_virt_cnt_read,
},
{ .name = "CNTPCTSS", .cp = 15, .crm = 14, .opc1 = 8,
.access = PL0_R, .type = ARM_CP_64BIT | ARM_CP_NO_RAW | ARM_CP_IO,
.accessfn = gt_pct_access,
.readfn = gt_cnt_read, .resetfn = arm_cp_reset_ignore,
},
{ .name = "CNTPCTSS_EL0", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 3, .crn = 14, .crm = 0, .opc2 = 5,
.access = PL0_R, .type = ARM_CP_NO_RAW | ARM_CP_IO,
.accessfn = gt_pct_access, .readfn = gt_cnt_read,
},
};
#else
/*
@ -3422,6 +3450,18 @@ static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
},
};
/*
* CNTVCTSS_EL0 has the same trap conditions as CNTVCT_EL0, so it also
* is exposed to userspace by Linux.
*/
static const ARMCPRegInfo gen_timer_ecv_cp_reginfo[] = {
{ .name = "CNTVCTSS_EL0", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 3, .crn = 14, .crm = 0, .opc2 = 6,
.access = PL0_R, .type = ARM_CP_NO_RAW | ARM_CP_IO,
.readfn = gt_virt_cnt_read,
},
};
#endif
static void par_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
@ -9258,6 +9298,9 @@ void register_cp_regs_for_features(ARMCPU *cpu)
if (arm_feature(env, ARM_FEATURE_GENERIC_TIMER)) {
define_arm_cp_regs(cpu, generic_timer_cp_reginfo);
}
if (cpu_isar_feature(aa64_ecv_traps, cpu)) {
define_arm_cp_regs(cpu, gen_timer_ecv_cp_reginfo);
}
if (arm_feature(env, ARM_FEATURE_VAPA)) {
ARMCPRegInfo vapa_cp_reginfo[] = {
{ .name = "PAR", .cp = 15, .crn = 7, .crm = 4, .opc1 = 0, .opc2 = 0,