if (cpu_isar_feature(aa64_rme, cpu)) {
valid_mask |= SCR_NSE | SCR_GPF;
}
+ if (cpu_isar_feature(aa64_ecv, cpu)) {
+ valid_mask |= SCR_ECVEN;
+ }
} else {
valid_mask &= ~(SCR_RW | SCR_ST);
if (cpu_isar_feature(aa32_ras, cpu)) {
gt_update_irq(cpu, GTIMER_PHYS);
}
+static uint64_t gt_phys_raw_cnt_offset(CPUARMState *env)
+{
+ if ((env->cp15.scr_el3 & SCR_ECVEN) &&
+ FIELD_EX64(env->cp15.cnthctl_el2, CNTHCTL, ECV) &&
+ arm_is_el2_enabled(env) &&
+ (arm_hcr_el2_eff(env) & (HCR_E2H | HCR_TGE)) != (HCR_E2H | HCR_TGE)) {
+ return env->cp15.cntpoff_el2;
+ }
+ return 0;
+}
+
+static uint64_t gt_phys_cnt_offset(CPUARMState *env)
+{
+ if (arm_current_el(env) >= 2) {
+ return 0;
+ }
+ return gt_phys_raw_cnt_offset(env);
+}
+
static void gt_recalc_timer(ARMCPU *cpu, int timeridx)
{
ARMGenericTimer *gt = &cpu->env.cp15.c14_timer[timeridx];
* reset timer to when ISTATUS next has to change
*/
uint64_t offset = timeridx == GTIMER_VIRT ?
- cpu->env.cp15.cntvoff_el2 : 0;
+ cpu->env.cp15.cntvoff_el2 : gt_phys_raw_cnt_offset(&cpu->env);
uint64_t count = gt_get_countervalue(&cpu->env);
/* Note that this must be unsigned 64 bit arithmetic: */
int istatus = count - offset >= gt->cval;
static uint64_t gt_cnt_read(CPUARMState *env, const ARMCPRegInfo *ri)
{
- return gt_get_countervalue(env);
+ return gt_get_countervalue(env) - gt_phys_cnt_offset(env);
}
static uint64_t gt_virt_cnt_offset(CPUARMState *env)
case GTIMER_HYPVIRT:
offset = gt_virt_cnt_offset(env);
break;
+ case GTIMER_PHYS:
+ offset = gt_phys_cnt_offset(env);
+ break;
}
return (uint32_t)(env->cp15.c14_timer[timeridx].cval -
case GTIMER_HYPVIRT:
offset = gt_virt_cnt_offset(env);
break;
+ case GTIMER_PHYS:
+ offset = gt_phys_cnt_offset(env);
+ break;
}
trace_arm_gt_tval_write(timeridx, value);
R_CNTHCTL_EL1NVVCT_MASK |
R_CNTHCTL_EVNTIS_MASK;
}
+ if (cpu_isar_feature(aa64_ecv, cpu)) {
+ valid_mask |= R_CNTHCTL_ECV_MASK;
+ }
/* Clear RES0 bits */
value &= valid_mask;
},
};
+static CPAccessResult gt_cntpoff_access(CPUARMState *env,
+ const ARMCPRegInfo *ri,
+ bool isread)
+{
+ if (arm_current_el(env) == 2 && !(env->cp15.scr_el3 & SCR_ECVEN)) {
+ return CP_ACCESS_TRAP_EL3;
+ }
+ return CP_ACCESS_OK;
+}
+
+static void gt_cntpoff_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ ARMCPU *cpu = env_archcpu(env);
+
+ trace_arm_gt_cntpoff_write(value);
+ raw_write(env, ri, value);
+ gt_recalc_timer(cpu, GTIMER_PHYS);
+}
+
+static const ARMCPRegInfo gen_timer_cntpoff_reginfo = {
+ .name = "CNTPOFF_EL2", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 4, .crn = 14, .crm = 0, .opc2 = 6,
+ .access = PL2_RW, .type = ARM_CP_IO, .resetvalue = 0,
+ .accessfn = gt_cntpoff_access, .writefn = gt_cntpoff_write,
+ .nv2_redirect_offset = 0x1a8,
+ .fieldoffset = offsetof(CPUARMState, cp15.cntpoff_el2),
+};
#else
/*
if (cpu_isar_feature(aa64_ecv_traps, cpu)) {
define_arm_cp_regs(cpu, gen_timer_ecv_cp_reginfo);
}
+#ifndef CONFIG_USER_ONLY
+ if (cpu_isar_feature(aa64_ecv, cpu)) {
+ define_one_arm_cp_reg(cpu, &gen_timer_cntpoff_reginfo);
+ }
+#endif
if (arm_feature(env, ARM_FEATURE_VAPA)) {
ARMCPRegInfo vapa_cp_reginfo[] = {
{ .name = "PAR", .cp = 15, .crn = 7, .crm = 4, .opc1 = 0, .opc2 = 0,