When FEAT_SEL2 was implemented the SEL2 timers where missed. This
shows up when building the latest Hafnium with SPMC_AT_EL=2. The
actual implementation utilises the same logic as the rest of the
timers so all we need to do is:
- define the timers and their access functions
- conditionally add the correct system registers
- create a new accessfn as the rules are subtly different to the
existing secure timer
Fixes: e9152ee91c (target/arm: add ARMv8.4-SEL2 system registers)
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Cc: qemu-stable@nongnu.org
Cc: Andrei Homescu <ahomescu@google.com>
Cc: Arve Hjønnevåg <arve@google.com>
Cc: Rémi Denis-Courmont <remi.denis.courmont@huawei.com>
---
v1
- add better comments to GTIMER descriptions
- also define new timers for sbsa-ref
- don't conditionally gate qemu_timer creation on the feature
- take cntvoff_el2 int account for SEC_VEL2 in gt_recalc/g_tval_[read|write]
v2
- rename IRQ to ARCH_TIMER_S_EL2_VIRT_IRQ
- split machine enablement into separate patches
- return CP_ACCESS_TRAP_UNCATEGORIZED for UNDEF cases
---
include/hw/arm/bsa.h | 2 +
target/arm/cpu.h | 2 +
target/arm/gtimer.h | 4 +-
target/arm/cpu.c | 4 ++
target/arm/helper.c | 158 +++++++++++++++++++++++++++++++++++++++++++
5 files changed, 169 insertions(+), 1 deletion(-)
diff --git a/include/hw/arm/bsa.h b/include/hw/arm/bsa.h
index 8eaab603c0..13ed2d2ac1 100644
--- a/include/hw/arm/bsa.h
+++ b/include/hw/arm/bsa.h
@@ -22,6 +22,8 @@
#define QEMU_ARM_BSA_H
/* These are architectural INTID values */
+#define ARCH_TIMER_S_EL2_VIRT_IRQ 19
+#define ARCH_TIMER_S_EL2_IRQ 20
#define VIRTUAL_PMU_IRQ 23
#define ARCH_GIC_MAINT_IRQ 25
#define ARCH_TIMER_NS_EL2_IRQ 26
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index d86e641280..10b5354d6f 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -1139,6 +1139,8 @@ void arm_gt_vtimer_cb(void *opaque);
void arm_gt_htimer_cb(void *opaque);
void arm_gt_stimer_cb(void *opaque);
void arm_gt_hvtimer_cb(void *opaque);
+void arm_gt_sel2timer_cb(void *opaque);
+void arm_gt_sel2vtimer_cb(void *opaque);
unsigned int gt_cntfrq_period_ns(ARMCPU *cpu);
void gt_rme_post_el_change(ARMCPU *cpu, void *opaque);
diff --git a/target/arm/gtimer.h b/target/arm/gtimer.h
index de016e6da3..f8f7425a5f 100644
--- a/target/arm/gtimer.h
+++ b/target/arm/gtimer.h
@@ -15,7 +15,9 @@ enum {
GTIMER_HYP = 2, /* EL2 physical timer */
GTIMER_SEC = 3, /* EL3 physical timer */
GTIMER_HYPVIRT = 4, /* EL2 virtual timer */
-#define NUM_GTIMERS 5
+ GTIMER_SEC_PEL2 = 5, /* Secure EL2 physical timer */
+ GTIMER_SEC_VEL2 = 6, /* Secure EL2 virtual timer */
+#define NUM_GTIMERS 7
};
#endif
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 1afa07511e..631cc2728d 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -2088,6 +2088,10 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
arm_gt_stimer_cb, cpu);
cpu->gt_timer[GTIMER_HYPVIRT] = timer_new(QEMU_CLOCK_VIRTUAL, scale,
arm_gt_hvtimer_cb, cpu);
+ cpu->gt_timer[GTIMER_SEC_PEL2] = timer_new(QEMU_CLOCK_VIRTUAL, scale,
+ arm_gt_sel2timer_cb, cpu);
+ cpu->gt_timer[GTIMER_SEC_VEL2] = timer_new(QEMU_CLOCK_VIRTUAL, scale,
+ arm_gt_sel2vtimer_cb, cpu);
}
#endif
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 5a1b416e18..79894b4802 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -2401,6 +2401,41 @@ 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:
+ return CP_ACCESS_TRAP;
+ case 1:
+ if (!arm_is_secure(env)) {
+ return CP_ACCESS_TRAP_UNCATEGORIZED;
+ } else if (arm_hcr_el2_eff(env) & HCR_NV) {
+ return CP_ACCESS_TRAP_EL2;
+ }
+ return CP_ACCESS_TRAP;
+ case 2:
+ if (!arm_is_secure(env)) {
+ return CP_ACCESS_TRAP_UNCATEGORIZED;
+ }
+ return CP_ACCESS_OK;
+ case 3:
+ if (env->cp15.scr_el3 & SCR_EEL2) {
+ return CP_ACCESS_OK;
+ } else {
+ return CP_ACCESS_TRAP_UNCATEGORIZED;
+ }
+ default:
+ g_assert_not_reached();
+ }
+}
+
uint64_t gt_get_countervalue(CPUARMState *env)
{
ARMCPU *cpu = env_archcpu(env);
@@ -2477,6 +2512,7 @@ static void gt_recalc_timer(ARMCPU *cpu, int timeridx)
switch (timeridx) {
case GTIMER_VIRT:
case GTIMER_HYPVIRT:
+ case GTIMER_SEC_VEL2:
offset = cpu->env.cp15.cntvoff_el2;
break;
default:
@@ -2591,6 +2627,7 @@ static uint64_t gt_tval_read(CPUARMState *env, const ARMCPRegInfo *ri,
switch (timeridx) {
case GTIMER_VIRT:
case GTIMER_HYPVIRT:
+ case GTIMER_SEC_VEL2:
offset = gt_virt_cnt_offset(env);
break;
case GTIMER_PHYS:
@@ -2611,6 +2648,7 @@ static void gt_tval_write(CPUARMState *env, const ARMCPRegInfo *ri,
switch (timeridx) {
case GTIMER_VIRT:
case GTIMER_HYPVIRT:
+ case GTIMER_SEC_VEL2:
offset = gt_virt_cnt_offset(env);
break;
case GTIMER_PHYS:
@@ -2919,6 +2957,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_SEC_PEL2);
+}
+
+static void gt_sec_pel2_cval_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ gt_cval_write(env, ri, GTIMER_SEC_PEL2, value);
+}
+
+static uint64_t gt_sec_pel2_tval_read(CPUARMState *env, const ARMCPRegInfo *ri)
+{
+ return gt_tval_read(env, ri, GTIMER_SEC_PEL2);
+}
+
+static void gt_sec_pel2_tval_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ gt_tval_write(env, ri, GTIMER_SEC_PEL2, value);
+}
+
+static void gt_sec_pel2_ctl_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ gt_ctl_write(env, ri, GTIMER_SEC_PEL2, value);
+}
+
+static void gt_sec_vel2_timer_reset(CPUARMState *env, const ARMCPRegInfo *ri)
+{
+ gt_timer_reset(env, ri, GTIMER_SEC_VEL2);
+}
+
+static void gt_sec_vel2_cval_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ gt_cval_write(env, ri, GTIMER_SEC_VEL2, value);
+}
+
+static uint64_t gt_sec_vel2_tval_read(CPUARMState *env, const ARMCPRegInfo *ri)
+{
+ return gt_tval_read(env, ri, GTIMER_SEC_VEL2);
+}
+
+static void gt_sec_vel2_tval_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ gt_tval_write(env, ri, GTIMER_SEC_VEL2, value);
+}
+
+static void gt_sec_vel2_ctl_write(CPUARMState *env, const ARMCPRegInfo *ri,
+ uint64_t value)
+{
+ gt_ctl_write(env, ri, GTIMER_SEC_VEL2, value);
+}
+
static void gt_hv_timer_reset(CPUARMState *env, const ARMCPRegInfo *ri)
{
gt_timer_reset(env, ri, GTIMER_HYPVIRT);
@@ -2975,6 +3069,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_SEC_PEL2);
+}
+
+void arm_gt_sel2vtimer_cb(void *opaque)
+{
+ ARMCPU *cpu = opaque;
+
+ gt_recalc_timer(cpu, GTIMER_SEC_VEL2);
+}
+
void arm_gt_hvtimer_cb(void *opaque)
{
ARMCPU *cpu = opaque;
@@ -5696,6 +5804,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_SEC_PEL2].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_SEC_PEL2].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_SEC_VEL2].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_SEC_VEL2].cval),
+ .writefn = gt_sec_vel2_cval_write, .raw_writefn = raw_write,
+ },
+#endif
};
static CPAccessResult nsacr_access(CPUARMState *env, const ARMCPRegInfo *ri,
--
2.39.5
On Wed, 18 Dec 2024 at 18:15, Alex Bennée <alex.bennee@linaro.org> wrote:
>
> When FEAT_SEL2 was implemented the SEL2 timers where missed. This
> shows up when building the latest Hafnium with SPMC_AT_EL=2. The
> actual implementation utilises the same logic as the rest of the
> timers so all we need to do is:
>
> - define the timers and their access functions
> - conditionally add the correct system registers
> - create a new accessfn as the rules are subtly different to the
> existing secure timer
>
> Fixes: e9152ee91c (target/arm: add ARMv8.4-SEL2 system registers)
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> Cc: qemu-stable@nongnu.org
> Cc: Andrei Homescu <ahomescu@google.com>
> Cc: Arve Hjønnevåg <arve@google.com>
> Cc: Rémi Denis-Courmont <remi.denis.courmont@huawei.com>
>
> ---
> v1
> - add better comments to GTIMER descriptions
> - also define new timers for sbsa-ref
> - don't conditionally gate qemu_timer creation on the feature
> - take cntvoff_el2 int account for SEC_VEL2 in gt_recalc/g_tval_[read|write]
> v2
> - rename IRQ to ARCH_TIMER_S_EL2_VIRT_IRQ
> - split machine enablement into separate patches
> - return CP_ACCESS_TRAP_UNCATEGORIZED for UNDEF cases
> ---
> +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:
> + return CP_ACCESS_TRAP;
> + case 1:
> + if (!arm_is_secure(env)) {
> + return CP_ACCESS_TRAP_UNCATEGORIZED;
> + } else if (arm_hcr_el2_eff(env) & HCR_NV) {
> + return CP_ACCESS_TRAP_EL2;
> + }
> + return CP_ACCESS_TRAP;
> + case 2:
> + if (!arm_is_secure(env)) {
> + return CP_ACCESS_TRAP_UNCATEGORIZED;
> + }
> + return CP_ACCESS_OK;
> + case 3:
> + if (env->cp15.scr_el3 & SCR_EEL2) {
> + return CP_ACCESS_OK;
> + } else {
> + return CP_ACCESS_TRAP_UNCATEGORIZED;
> + }
> + default:
> + g_assert_not_reached();
> + }
> +}
This code is still using CP_ACCESS_TRAP in some codepaths, which
isn't correct. Either:
* you want an UNDEF: that's CP_ACCESS_TRAP_UNCATEGORIZED
* you want to trap to some specific EL: that's CP_ACCESS_TRAP_EL2
or CP_ACCESS_TRAP_EL3 depending on where you need to trap to.
thanks
-- PMM
On 18/12/24 19:15, Alex Bennée wrote:
> When FEAT_SEL2 was implemented the SEL2 timers where missed. This
> shows up when building the latest Hafnium with SPMC_AT_EL=2. The
> actual implementation utilises the same logic as the rest of the
> timers so all we need to do is:
>
> - define the timers and their access functions
> - conditionally add the correct system registers
> - create a new accessfn as the rules are subtly different to the
> existing secure timer
>
> Fixes: e9152ee91c (target/arm: add ARMv8.4-SEL2 system registers)
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> Cc: qemu-stable@nongnu.org
> Cc: Andrei Homescu <ahomescu@google.com>
> Cc: Arve Hjønnevåg <arve@google.com>
> Cc: Rémi Denis-Courmont <remi.denis.courmont@huawei.com>
>
> ---
> v1
> - add better comments to GTIMER descriptions
> - also define new timers for sbsa-ref
> - don't conditionally gate qemu_timer creation on the feature
> - take cntvoff_el2 int account for SEC_VEL2 in gt_recalc/g_tval_[read|write]
> v2
> - rename IRQ to ARCH_TIMER_S_EL2_VIRT_IRQ
> - split machine enablement into separate patches
> - return CP_ACCESS_TRAP_UNCATEGORIZED for UNDEF cases
> ---
> include/hw/arm/bsa.h | 2 +
> target/arm/cpu.h | 2 +
> target/arm/gtimer.h | 4 +-
> target/arm/cpu.c | 4 ++
> target/arm/helper.c | 158 +++++++++++++++++++++++++++++++++++++++++++
> 5 files changed, 169 insertions(+), 1 deletion(-)
> diff --git a/target/arm/gtimer.h b/target/arm/gtimer.h
> index de016e6da3..f8f7425a5f 100644
> --- a/target/arm/gtimer.h
> +++ b/target/arm/gtimer.h
> @@ -15,7 +15,9 @@ enum {
> GTIMER_HYP = 2, /* EL2 physical timer */
> GTIMER_SEC = 3, /* EL3 physical timer */
Should we rename as GTIMER_SEC_PEL3 for consistency?
> GTIMER_HYPVIRT = 4, /* EL2 virtual timer */
Also GTIMER_HYP -> GTIMER_PEL2,
GTIMER_HYPVIRT -> GTIMER_VEL2?
> -#define NUM_GTIMERS 5
> + GTIMER_SEC_PEL2 = 5, /* Secure EL2 physical timer */
> + GTIMER_SEC_VEL2 = 6, /* Secure EL2 virtual timer */
> +#define NUM_GTIMERS 7
> };
>
> #endif|
It's not the context that lacks its the protocol.. lol. I wish I was good
with words and a genius... oh no wait. It's easier being simple..you
think.u could find the s
B listers. There's gotta b a mpatch
On Thu, Jan 9, 2025, 5:19 AM Philippe Mathieu-Daudé <philmd@linaro.org>
wrote:
> On 18/12/24 19:15, Alex Bennée wrote:
> > When FEAT_SEL2 was implemented the SEL2 timers where missed. This
> > shows up when building the latest Hafnium with SPMC_AT_EL=2. The
> > actual implementation utilises the same logic as the rest of the
> > timers so all we need to do is:
> >
> > - define the timers and their access functions
> > - conditionally add the correct system registers
> > - create a new accessfn as the rules are subtly different to the
> > existing secure timer
> >
> > Fixes: e9152ee91c (target/arm: add ARMv8.4-SEL2 system registers)
> > Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> > Cc: qemu-stable@nongnu.org
> > Cc: Andrei Homescu <ahomescu@google.com>
> > Cc: Arve Hjønnevåg <arve@google.com>
> > Cc: Rémi Denis-Courmont <remi.denis.courmont@huawei.com>
> >
> > ---
> > v1
> > - add better comments to GTIMER descriptions
> > - also define new timers for sbsa-ref
> > - don't conditionally gate qemu_timer creation on the feature
> > - take cntvoff_el2 int account for SEC_VEL2 in
> gt_recalc/g_tval_[read|write]
> > v2
> > - rename IRQ to ARCH_TIMER_S_EL2_VIRT_IRQ
> > - split machine enablement into separate patches
> > - return CP_ACCESS_TRAP_UNCATEGORIZED for UNDEF cases
> > ---
> > include/hw/arm/bsa.h | 2 +
> > target/arm/cpu.h | 2 +
> > target/arm/gtimer.h | 4 +-
> > target/arm/cpu.c | 4 ++
> > target/arm/helper.c | 158 +++++++++++++++++++++++++++++++++++++++++++
> > 5 files changed, 169 insertions(+), 1 deletion(-)
>
>
> > diff --git a/target/arm/gtimer.h b/target/arm/gtimer.h
> > index de016e6da3..f8f7425a5f 100644
> > --- a/target/arm/gtimer.h
> > +++ b/target/arm/gtimer.h
> > @@ -15,7 +15,9 @@ enum {
> > GTIMER_HYP = 2, /* EL2 physical timer */
> > GTIMER_SEC = 3, /* EL3 physical timer */
>
> Should we rename as GTIMER_SEC_PEL3 for consistency?
>
> > GTIMER_HYPVIRT = 4, /* EL2 virtual timer */
>
> Also GTIMER_HYP -> GTIMER_PEL2,
> GTIMER_HYPVIRT -> GTIMER_VEL2?
>
> > -#define NUM_GTIMERS 5
> > + GTIMER_SEC_PEL2 = 5, /* Secure EL2 physical timer */
> > + GTIMER_SEC_VEL2 = 6, /* Secure EL2 virtual timer */
> > +#define NUM_GTIMERS 7
> > };
> >
> > #endif|
>
>
© 2016 - 2026 Red Hat, Inc.