Add the register_time_change_notifier method to the RISCVCPUTimeSrcIf
interface. This method allows the time source user to register a
notifier on tick counter asynchronous modification (i.e., a modification
that is not due to the monotonic nature of the counter). This can happen
if the time source counter is writable, which is the case of the `time'
register of the ACLINT.
Use this mechanism in time_helper.c to recompute the sstc timers
deadlines.
Signed-off-by: Luc Michel <luc.michel@amd.com>
---
target/riscv/cpu-qom.h | 7 +++++++
target/riscv/cpu.h | 1 +
target/riscv/time_helper.h | 11 +++++++++++
target/riscv/time_helper.c | 13 +++++++++++++
4 files changed, 32 insertions(+)
diff --git a/target/riscv/cpu-qom.h b/target/riscv/cpu-qom.h
index e5bc23b2ef5..29cb30d23a9 100644
--- a/target/riscv/cpu-qom.h
+++ b/target/riscv/cpu-qom.h
@@ -90,8 +90,15 @@ struct RISCVCPUTimeSrcIfClass {
/**
* get_tick_freq: get the tick frequency of this time source.
*/
uint32_t (*get_tick_freq)(RISCVCPUTimeSrcIf *);
+
+ /*
+ * register_time_change_notifier: register a notifier which get notified
+ * when the value of the free running counter observes a discontinuity
+ * (e.g., the counter value gets reset to 0).
+ */
+ void (*register_time_change_notifier)(RISCVCPUTimeSrcIf *, Notifier *);
};
#endif /* RISCV_CPU_QOM_H */
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 368b9e2532d..40b198d8d4a 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -460,10 +460,11 @@ struct CPUArchState {
int64_t last_icount;
bool itrigger_enabled;
/* machine specific time source interface */
RISCVCPUTimeSrcIf *time_src;
+ Notifier time_change_notifier;
/* machine specific AIA ireg read-modify-write callback */
#define AIA_MAKE_IREG(__isel, __priv, __virt, __vgein, __xlen) \
((((__xlen) & 0xff) << 24) | \
(((__vgein) & 0x3f) << 20) | \
diff --git a/target/riscv/time_helper.h b/target/riscv/time_helper.h
index b51fdd96570..074b516f4ad 100644
--- a/target/riscv/time_helper.h
+++ b/target/riscv/time_helper.h
@@ -42,6 +42,17 @@ static inline uint32_t riscv_cpu_time_src_get_tick_freq(RISCVCPUTimeSrcIf *src)
g_assert(rctsc->get_tick_freq != NULL);
return rctsc->get_tick_freq(src);
}
+static inline void
+riscv_cpu_time_src_register_time_change_notifier(RISCVCPUTimeSrcIf *src,
+ Notifier *notifier)
+{
+ RISCVCPUTimeSrcIfClass *rctsc = RISCV_CPU_TIME_SRC_IF_GET_CLASS(src);
+
+ if (rctsc->register_time_change_notifier) {
+ rctsc->register_time_change_notifier(src, notifier);
+ }
+}
+
#endif
diff --git a/target/riscv/time_helper.c b/target/riscv/time_helper.c
index 7b493b7a233..b1d7bba1afe 100644
--- a/target/riscv/time_helper.c
+++ b/target/riscv/time_helper.c
@@ -181,10 +181,19 @@ void riscv_timer_stce_changed(CPURISCVState *env, bool is_m_mode, bool enable)
riscv_timer_disable_timecmp(env, env->stimer, MIP_STIP);
}
}
}
+static void time_src_ticks_change_cb(Notifier *notifier, void *opaque)
+{
+ CPURISCVState *env = container_of(notifier, CPURISCVState, time_change_notifier);
+
+ riscv_timer_write_timecmp(env, env->stimer, env->stimecmp, 0, MIP_STIP);
+ riscv_timer_write_timecmp(env, env->vstimer, env->vstimecmp,
+ env->htimedelta, MIP_VSTIP);
+}
+
void riscv_timer_init(RISCVCPU *cpu)
{
CPURISCVState *env;
if (!cpu) {
@@ -200,10 +209,14 @@ void riscv_timer_init(RISCVCPU *cpu)
}
void riscv_cpu_set_time_src(CPURISCVState *env, RISCVCPUTimeSrcIf *src)
{
env->time_src = src;
+ env->time_change_notifier.notify = time_src_ticks_change_cb;
+
+ riscv_cpu_time_src_register_time_change_notifier(src,
+ &env->time_change_notifier);
}
static const TypeInfo riscv_cpu_time_src_if_info = {
.name = TYPE_RISCV_CPU_TIME_SRC_IF,
.parent = TYPE_INTERFACE,
--
2.51.0
On 7/11/25 11:23, Luc Michel wrote:
> Add the register_time_change_notifier method to the RISCVCPUTimeSrcIf
> interface. This method allows the time source user to register a
> notifier on tick counter asynchronous modification (i.e., a modification
> that is not due to the monotonic nature of the counter). This can happen
> if the time source counter is writable, which is the case of the `time'
> register of the ACLINT.
>
> Use this mechanism in time_helper.c to recompute the sstc timers
> deadlines.
>
> Signed-off-by: Luc Michel <luc.michel@amd.com>
> ---
> target/riscv/cpu-qom.h | 7 +++++++
> target/riscv/cpu.h | 1 +
> target/riscv/time_helper.h | 11 +++++++++++
> target/riscv/time_helper.c | 13 +++++++++++++
> 4 files changed, 32 insertions(+)
> diff --git a/target/riscv/time_helper.h b/target/riscv/time_helper.h
> index b51fdd96570..074b516f4ad 100644
> --- a/target/riscv/time_helper.h
> +++ b/target/riscv/time_helper.h
> @@ -42,6 +42,17 @@ static inline uint32_t riscv_cpu_time_src_get_tick_freq(RISCVCPUTimeSrcIf *src)
>
> g_assert(rctsc->get_tick_freq != NULL);
> return rctsc->get_tick_freq(src);
> }
>
> +static inline void
> +riscv_cpu_time_src_register_time_change_notifier(RISCVCPUTimeSrcIf *src,
> + Notifier *notifier)
> +{
> + RISCVCPUTimeSrcIfClass *rctsc = RISCV_CPU_TIME_SRC_IF_GET_CLASS(src);
> +
> + if (rctsc->register_time_change_notifier) {
> + rctsc->register_time_change_notifier(src, notifier);
> + }
What about some trace event to help developers? I.e.:
if (!rctsc->register_time_change_notifier) {
trace_riscv_cpu_time_src_register_time_change_without_notifier();
return;
}
rctsc->register_time_change_notifier(src, notifier);
> +}
Anyhow:
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Hi Phil,
On 18:20 Thu 20 Nov , Philippe Mathieu-Daudé wrote:
> On 7/11/25 11:23, Luc Michel wrote:
> > Add the register_time_change_notifier method to the RISCVCPUTimeSrcIf
> > interface. This method allows the time source user to register a
> > notifier on tick counter asynchronous modification (i.e., a modification
> > that is not due to the monotonic nature of the counter). This can happen
> > if the time source counter is writable, which is the case of the `time'
> > register of the ACLINT.
> >
> > Use this mechanism in time_helper.c to recompute the sstc timers
> > deadlines.
> >
> > Signed-off-by: Luc Michel <luc.michel@amd.com>
> > ---
> > target/riscv/cpu-qom.h | 7 +++++++
> > target/riscv/cpu.h | 1 +
> > target/riscv/time_helper.h | 11 +++++++++++
> > target/riscv/time_helper.c | 13 +++++++++++++
> > 4 files changed, 32 insertions(+)
>
>
> > diff --git a/target/riscv/time_helper.h b/target/riscv/time_helper.h
> > index b51fdd96570..074b516f4ad 100644
> > --- a/target/riscv/time_helper.h
> > +++ b/target/riscv/time_helper.h
> > @@ -42,6 +42,17 @@ static inline uint32_t riscv_cpu_time_src_get_tick_freq(RISCVCPUTimeSrcIf *src)
> >
> > g_assert(rctsc->get_tick_freq != NULL);
> > return rctsc->get_tick_freq(src);
> > }
> >
> > +static inline void
> > +riscv_cpu_time_src_register_time_change_notifier(RISCVCPUTimeSrcIf *src,
> > + Notifier *notifier)
> > +{
> > + RISCVCPUTimeSrcIfClass *rctsc = RISCV_CPU_TIME_SRC_IF_GET_CLASS(src);
> > +
> > + if (rctsc->register_time_change_notifier) {
> > + rctsc->register_time_change_notifier(src, notifier);
> > + }
>
> What about some trace event to help developers? I.e.:
I made this method optional in case the time source is read-only. In
this case there is no need for a notifier as it cannot change
asynchronously.
--
Luc
>
> if (!rctsc->register_time_change_notifier) {
> trace_riscv_cpu_time_src_register_time_change_without_notifier();
> return;
> }
> rctsc->register_time_change_notifier(src, notifier);
>
> > +}
>
> Anyhow:
> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
>
--
© 2016 - 2026 Red Hat, Inc.