|
@@ -2404,6 +2404,45 @@ static CPAccessResult gt_stimer_access(CPUARMState *env,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static CPAccessResult gt_sel2timer_access(CPUARMState *env,
|
|
|
+ const ARMCPRegInfo *ri,
|
|
|
+ bool isread)
|
|
|
+{
|
|
|
+ /*
|
|
|
+ * The AArch64 register view of the secure EL2 timers are mostly
|
|
|
+ * accessible from EL3 and EL2 although can also be trapped to EL2
|
|
|
+ * from EL1 depending on nested virt config.
|
|
|
+ */
|
|
|
+ switch (arm_current_el(env)) {
|
|
|
+ case 0: /* UNDEFINED */
|
|
|
+ return CP_ACCESS_UNDEFINED;
|
|
|
+ case 1:
|
|
|
+ if (!arm_is_secure(env)) {
|
|
|
+ /* UNDEFINED */
|
|
|
+ return CP_ACCESS_UNDEFINED;
|
|
|
+ } else if (arm_hcr_el2_eff(env) & HCR_NV) {
|
|
|
+ /* Aarch64.SystemAccessTrap(EL2, 0x18) */
|
|
|
+ return CP_ACCESS_TRAP_EL2;
|
|
|
+ }
|
|
|
+ /* UNDEFINED */
|
|
|
+ return CP_ACCESS_UNDEFINED;
|
|
|
+ case 2:
|
|
|
+ if (!arm_is_secure(env)) {
|
|
|
+ /* UNDEFINED */
|
|
|
+ return CP_ACCESS_UNDEFINED;
|
|
|
+ }
|
|
|
+ return CP_ACCESS_OK;
|
|
|
+ case 3:
|
|
|
+ if (env->cp15.scr_el3 & SCR_EEL2) {
|
|
|
+ return CP_ACCESS_OK;
|
|
|
+ } else {
|
|
|
+ return CP_ACCESS_UNDEFINED;
|
|
|
+ }
|
|
|
+ default:
|
|
|
+ g_assert_not_reached();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
uint64_t gt_get_countervalue(CPUARMState *env)
|
|
|
{
|
|
|
ARMCPU *cpu = env_archcpu(env);
|
|
@@ -2475,6 +2514,8 @@ static uint64_t gt_indirect_access_timer_offset(CPUARMState *env, int timeridx)
|
|
|
case GTIMER_HYP:
|
|
|
case GTIMER_SEC:
|
|
|
case GTIMER_HYPVIRT:
|
|
|
+ case GTIMER_S_EL2_PHYS:
|
|
|
+ case GTIMER_S_EL2_VIRT:
|
|
|
return 0;
|
|
|
default:
|
|
|
g_assert_not_reached();
|
|
@@ -2521,6 +2562,8 @@ uint64_t gt_direct_access_timer_offset(CPUARMState *env, int timeridx)
|
|
|
case GTIMER_HYP:
|
|
|
case GTIMER_SEC:
|
|
|
case GTIMER_HYPVIRT:
|
|
|
+ case GTIMER_S_EL2_PHYS:
|
|
|
+ case GTIMER_S_EL2_VIRT:
|
|
|
return 0;
|
|
|
default:
|
|
|
g_assert_not_reached();
|
|
@@ -2953,6 +2996,62 @@ static void gt_sec_ctl_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
|
|
gt_ctl_write(env, ri, GTIMER_SEC, value);
|
|
|
}
|
|
|
|
|
|
+static void gt_sec_pel2_timer_reset(CPUARMState *env, const ARMCPRegInfo *ri)
|
|
|
+{
|
|
|
+ gt_timer_reset(env, ri, GTIMER_S_EL2_PHYS);
|
|
|
+}
|
|
|
+
|
|
|
+static void gt_sec_pel2_cval_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
|
|
+ uint64_t value)
|
|
|
+{
|
|
|
+ gt_cval_write(env, ri, GTIMER_S_EL2_PHYS, value);
|
|
|
+}
|
|
|
+
|
|
|
+static uint64_t gt_sec_pel2_tval_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
|
|
+{
|
|
|
+ return gt_tval_read(env, ri, GTIMER_S_EL2_PHYS);
|
|
|
+}
|
|
|
+
|
|
|
+static void gt_sec_pel2_tval_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
|
|
+ uint64_t value)
|
|
|
+{
|
|
|
+ gt_tval_write(env, ri, GTIMER_S_EL2_PHYS, value);
|
|
|
+}
|
|
|
+
|
|
|
+static void gt_sec_pel2_ctl_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
|
|
+ uint64_t value)
|
|
|
+{
|
|
|
+ gt_ctl_write(env, ri, GTIMER_S_EL2_PHYS, value);
|
|
|
+}
|
|
|
+
|
|
|
+static void gt_sec_vel2_timer_reset(CPUARMState *env, const ARMCPRegInfo *ri)
|
|
|
+{
|
|
|
+ gt_timer_reset(env, ri, GTIMER_S_EL2_VIRT);
|
|
|
+}
|
|
|
+
|
|
|
+static void gt_sec_vel2_cval_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
|
|
+ uint64_t value)
|
|
|
+{
|
|
|
+ gt_cval_write(env, ri, GTIMER_S_EL2_VIRT, value);
|
|
|
+}
|
|
|
+
|
|
|
+static uint64_t gt_sec_vel2_tval_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
|
|
+{
|
|
|
+ return gt_tval_read(env, ri, GTIMER_S_EL2_VIRT);
|
|
|
+}
|
|
|
+
|
|
|
+static void gt_sec_vel2_tval_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
|
|
+ uint64_t value)
|
|
|
+{
|
|
|
+ gt_tval_write(env, ri, GTIMER_S_EL2_VIRT, value);
|
|
|
+}
|
|
|
+
|
|
|
+static void gt_sec_vel2_ctl_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
|
|
+ uint64_t value)
|
|
|
+{
|
|
|
+ gt_ctl_write(env, ri, GTIMER_S_EL2_VIRT, value);
|
|
|
+}
|
|
|
+
|
|
|
static void gt_hv_timer_reset(CPUARMState *env, const ARMCPRegInfo *ri)
|
|
|
{
|
|
|
gt_timer_reset(env, ri, GTIMER_HYPVIRT);
|
|
@@ -3009,6 +3108,20 @@ void arm_gt_stimer_cb(void *opaque)
|
|
|
gt_recalc_timer(cpu, GTIMER_SEC);
|
|
|
}
|
|
|
|
|
|
+void arm_gt_sel2timer_cb(void *opaque)
|
|
|
+{
|
|
|
+ ARMCPU *cpu = opaque;
|
|
|
+
|
|
|
+ gt_recalc_timer(cpu, GTIMER_S_EL2_PHYS);
|
|
|
+}
|
|
|
+
|
|
|
+void arm_gt_sel2vtimer_cb(void *opaque)
|
|
|
+{
|
|
|
+ ARMCPU *cpu = opaque;
|
|
|
+
|
|
|
+ gt_recalc_timer(cpu, GTIMER_S_EL2_VIRT);
|
|
|
+}
|
|
|
+
|
|
|
void arm_gt_hvtimer_cb(void *opaque)
|
|
|
{
|
|
|
ARMCPU *cpu = opaque;
|
|
@@ -5733,6 +5846,56 @@ static const ARMCPRegInfo el2_sec_cp_reginfo[] = {
|
|
|
.access = PL2_RW, .accessfn = sel2_access,
|
|
|
.nv2_redirect_offset = 0x48,
|
|
|
.fieldoffset = offsetof(CPUARMState, cp15.vstcr_el2) },
|
|
|
+#ifndef CONFIG_USER_ONLY
|
|
|
+ /* Secure EL2 Physical Timer */
|
|
|
+ { .name = "CNTHPS_TVAL_EL2", .state = ARM_CP_STATE_AA64,
|
|
|
+ .opc0 = 3, .opc1 = 4, .crn = 14, .crm = 5, .opc2 = 0,
|
|
|
+ .type = ARM_CP_NO_RAW | ARM_CP_IO, .access = PL2_RW,
|
|
|
+ .accessfn = gt_sel2timer_access,
|
|
|
+ .readfn = gt_sec_pel2_tval_read,
|
|
|
+ .writefn = gt_sec_pel2_tval_write,
|
|
|
+ .resetfn = gt_sec_pel2_timer_reset,
|
|
|
+ },
|
|
|
+ { .name = "CNTHPS_CTL_EL2", .state = ARM_CP_STATE_AA64,
|
|
|
+ .opc0 = 3, .opc1 = 4, .crn = 14, .crm = 5, .opc2 = 1,
|
|
|
+ .type = ARM_CP_IO, .access = PL2_RW,
|
|
|
+ .accessfn = gt_sel2timer_access,
|
|
|
+ .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_S_EL2_PHYS].ctl),
|
|
|
+ .resetvalue = 0,
|
|
|
+ .writefn = gt_sec_pel2_ctl_write, .raw_writefn = raw_write,
|
|
|
+ },
|
|
|
+ { .name = "CNTHPS_CVAL_EL2", .state = ARM_CP_STATE_AA64,
|
|
|
+ .opc0 = 3, .opc1 = 4, .crn = 14, .crm = 5, .opc2 = 2,
|
|
|
+ .type = ARM_CP_IO, .access = PL2_RW,
|
|
|
+ .accessfn = gt_sel2timer_access,
|
|
|
+ .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_S_EL2_PHYS].cval),
|
|
|
+ .writefn = gt_sec_pel2_cval_write, .raw_writefn = raw_write,
|
|
|
+ },
|
|
|
+ /* Secure EL2 Virtual Timer */
|
|
|
+ { .name = "CNTHVS_TVAL_EL2", .state = ARM_CP_STATE_AA64,
|
|
|
+ .opc0 = 3, .opc1 = 4, .crn = 14, .crm = 4, .opc2 = 0,
|
|
|
+ .type = ARM_CP_NO_RAW | ARM_CP_IO, .access = PL2_RW,
|
|
|
+ .accessfn = gt_sel2timer_access,
|
|
|
+ .readfn = gt_sec_vel2_tval_read,
|
|
|
+ .writefn = gt_sec_vel2_tval_write,
|
|
|
+ .resetfn = gt_sec_vel2_timer_reset,
|
|
|
+ },
|
|
|
+ { .name = "CNTHVS_CTL_EL2", .state = ARM_CP_STATE_AA64,
|
|
|
+ .opc0 = 3, .opc1 = 4, .crn = 14, .crm = 4, .opc2 = 1,
|
|
|
+ .type = ARM_CP_IO, .access = PL2_RW,
|
|
|
+ .accessfn = gt_sel2timer_access,
|
|
|
+ .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_S_EL2_VIRT].ctl),
|
|
|
+ .resetvalue = 0,
|
|
|
+ .writefn = gt_sec_vel2_ctl_write, .raw_writefn = raw_write,
|
|
|
+ },
|
|
|
+ { .name = "CNTHVS_CVAL_EL2", .state = ARM_CP_STATE_AA64,
|
|
|
+ .opc0 = 3, .opc1 = 4, .crn = 14, .crm = 4, .opc2 = 2,
|
|
|
+ .type = ARM_CP_IO, .access = PL2_RW,
|
|
|
+ .accessfn = gt_sel2timer_access,
|
|
|
+ .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_S_EL2_VIRT].cval),
|
|
|
+ .writefn = gt_sec_vel2_cval_write, .raw_writefn = raw_write,
|
|
|
+ },
|
|
|
+#endif
|
|
|
};
|
|
|
|
|
|
static CPAccessResult nsacr_access(CPUARMState *env, const ARMCPRegInfo *ri,
|