* [PATCH 1/9] target/riscv: drop unused include directive in time_helper.c
2025-11-07 10:23 [PATCH 0/9] RISC-V CPU time source interface Luc Michel
@ 2025-11-07 10:23 ` Luc Michel
2025-11-09 14:03 ` Philippe Mathieu-Daudé
2025-11-07 10:23 ` [PATCH 2/9] hw/intc/riscv_aclint: fix coding style Luc Michel
` (8 subsequent siblings)
9 siblings, 1 reply; 21+ messages in thread
From: Luc Michel @ 2025-11-07 10:23 UTC (permalink / raw)
To: qemu-devel, qemu-riscv
Cc: Luc Michel, Palmer Dabbelt, Alistair Francis, Weiwei Li,
Daniel Henrique Barboza, Liu Zhiwei, Francisco Iglesias
Drop the unused qemu/log.h include directive in time_helper.c
Signed-off-by: Luc Michel <luc.michel@amd.com>
---
target/riscv/time_helper.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/target/riscv/time_helper.c b/target/riscv/time_helper.c
index 400e9173542..d2ec8a94166 100644
--- a/target/riscv/time_helper.c
+++ b/target/riscv/time_helper.c
@@ -15,11 +15,10 @@
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
-#include "qemu/log.h"
#include "cpu_bits.h"
#include "time_helper.h"
#include "hw/intc/riscv_aclint.h"
static void riscv_vstimer_cb(void *opaque)
--
2.51.0
^ permalink raw reply related [flat|nested] 21+ messages in thread* Re: [PATCH 1/9] target/riscv: drop unused include directive in time_helper.c
2025-11-07 10:23 ` [PATCH 1/9] target/riscv: drop unused include directive in time_helper.c Luc Michel
@ 2025-11-09 14:03 ` Philippe Mathieu-Daudé
0 siblings, 0 replies; 21+ messages in thread
From: Philippe Mathieu-Daudé @ 2025-11-09 14:03 UTC (permalink / raw)
To: Luc Michel, qemu-devel, qemu-riscv
Cc: Palmer Dabbelt, Alistair Francis, Weiwei Li,
Daniel Henrique Barboza, Liu Zhiwei, Francisco Iglesias
On 7/11/25 11:23, Luc Michel wrote:
> Drop the unused qemu/log.h include directive in time_helper.c
>
> Signed-off-by: Luc Michel <luc.michel@amd.com>
> ---
> target/riscv/time_helper.c | 1 -
> 1 file changed, 1 deletion(-)
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH 2/9] hw/intc/riscv_aclint: fix coding style
2025-11-07 10:23 [PATCH 0/9] RISC-V CPU time source interface Luc Michel
2025-11-07 10:23 ` [PATCH 1/9] target/riscv: drop unused include directive in time_helper.c Luc Michel
@ 2025-11-07 10:23 ` Luc Michel
2025-11-09 13:56 ` Philippe Mathieu-Daudé
2025-11-07 10:23 ` [PATCH 3/9] hw/intc/riscv_aclint: rename cpu_riscv_read_rtc to riscv_aclint_mtimer_get_ticks Luc Michel
` (7 subsequent siblings)
9 siblings, 1 reply; 21+ messages in thread
From: Luc Michel @ 2025-11-07 10:23 UTC (permalink / raw)
To: qemu-devel, qemu-riscv
Cc: Luc Michel, Palmer Dabbelt, Alistair Francis, Weiwei Li,
Daniel Henrique Barboza, Liu Zhiwei, Francisco Iglesias
Fix coding style in `riscv_aclint_mtimer_class_init' and
`riscv_aclint_swi_class_init' functions.
Signed-off-by: Luc Michel <luc.michel@amd.com>
---
hw/intc/riscv_aclint.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/hw/intc/riscv_aclint.c b/hw/intc/riscv_aclint.c
index c6f13f647ec..5f5ffc61e80 100644
--- a/hw/intc/riscv_aclint.c
+++ b/hw/intc/riscv_aclint.c
@@ -342,13 +342,14 @@ static const VMStateDescription vmstate_riscv_mtimer = {
};
static void riscv_aclint_mtimer_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+
dc->realize = riscv_aclint_mtimer_realize;
device_class_set_props(dc, riscv_aclint_mtimer_properties);
- ResettableClass *rc = RESETTABLE_CLASS(klass);
rc->phases.enter = riscv_aclint_mtimer_reset_enter;
dc->vmsd = &vmstate_riscv_mtimer;
}
static const TypeInfo riscv_aclint_mtimer_info = {
@@ -528,13 +529,14 @@ static void riscv_aclint_swi_reset_enter(Object *obj, ResetType type)
}
static void riscv_aclint_swi_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+
dc->realize = riscv_aclint_swi_realize;
device_class_set_props(dc, riscv_aclint_swi_properties);
- ResettableClass *rc = RESETTABLE_CLASS(klass);
rc->phases.enter = riscv_aclint_swi_reset_enter;
}
static const TypeInfo riscv_aclint_swi_info = {
.name = TYPE_RISCV_ACLINT_SWI,
--
2.51.0
^ permalink raw reply related [flat|nested] 21+ messages in thread* Re: [PATCH 2/9] hw/intc/riscv_aclint: fix coding style
2025-11-07 10:23 ` [PATCH 2/9] hw/intc/riscv_aclint: fix coding style Luc Michel
@ 2025-11-09 13:56 ` Philippe Mathieu-Daudé
0 siblings, 0 replies; 21+ messages in thread
From: Philippe Mathieu-Daudé @ 2025-11-09 13:56 UTC (permalink / raw)
To: Luc Michel, qemu-devel, qemu-riscv
Cc: Palmer Dabbelt, Alistair Francis, Weiwei Li,
Daniel Henrique Barboza, Liu Zhiwei, Francisco Iglesias
On 7/11/25 11:23, Luc Michel wrote:
> Fix coding style in `riscv_aclint_mtimer_class_init' and
> `riscv_aclint_swi_class_init' functions.
>
> Signed-off-by: Luc Michel <luc.michel@amd.com>
> ---
> hw/intc/riscv_aclint.c | 6 ++++--
> 1 file changed, 4 insertions(+), 2 deletions(-)
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH 3/9] hw/intc/riscv_aclint: rename cpu_riscv_read_rtc to riscv_aclint_mtimer_get_ticks
2025-11-07 10:23 [PATCH 0/9] RISC-V CPU time source interface Luc Michel
2025-11-07 10:23 ` [PATCH 1/9] target/riscv: drop unused include directive in time_helper.c Luc Michel
2025-11-07 10:23 ` [PATCH 2/9] hw/intc/riscv_aclint: fix coding style Luc Michel
@ 2025-11-07 10:23 ` Luc Michel
2025-11-09 13:56 ` Philippe Mathieu-Daudé
2025-11-07 10:23 ` [PATCH 4/9] target/riscv: add the RISCVCPUTimeSrcIf interface Luc Michel
` (6 subsequent siblings)
9 siblings, 1 reply; 21+ messages in thread
From: Luc Michel @ 2025-11-07 10:23 UTC (permalink / raw)
To: qemu-devel, qemu-riscv
Cc: Luc Michel, Palmer Dabbelt, Alistair Francis, Weiwei Li,
Daniel Henrique Barboza, Liu Zhiwei, Francisco Iglesias
For more clarity, rename the cpu_riscv_read_rtc function to
riscv_aclint_mtimer_get_ticks:
- The ACLINT is the time source here, not the CPU,
- This function returns a number of ticks based on the timer
frequency.
Rename the _raw version of this function as well and the local variables
storing the result of those function.
Signed-off-by: Luc Michel <luc.michel@amd.com>
---
hw/intc/riscv_aclint.c | 31 ++++++++++++++++---------------
1 file changed, 16 insertions(+), 15 deletions(-)
diff --git a/hw/intc/riscv_aclint.c b/hw/intc/riscv_aclint.c
index 5f5ffc61e80..95398e48821 100644
--- a/hw/intc/riscv_aclint.c
+++ b/hw/intc/riscv_aclint.c
@@ -38,20 +38,21 @@
typedef struct riscv_aclint_mtimer_callback {
RISCVAclintMTimerState *s;
int num;
} riscv_aclint_mtimer_callback;
-static uint64_t cpu_riscv_read_rtc_raw(uint32_t timebase_freq)
+static uint64_t riscv_aclint_mtimer_get_ticks_raw(uint32_t timebase_freq)
{
return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
timebase_freq, NANOSECONDS_PER_SECOND);
}
-static uint64_t cpu_riscv_read_rtc(void *opaque)
+static uint64_t riscv_aclint_mtimer_get_ticks(void *opaque)
{
RISCVAclintMTimerState *mtimer = opaque;
- return cpu_riscv_read_rtc_raw(mtimer->timebase_freq) + mtimer->time_delta;
+ return riscv_aclint_mtimer_get_ticks_raw(mtimer->timebase_freq) +
+ mtimer->time_delta;
}
/*
* Called when timecmp is written to update the QEMU timer or immediately
* trigger timer interrupt if mtimecmp <= current timer value.
@@ -63,28 +64,28 @@ static void riscv_aclint_mtimer_write_timecmp(RISCVAclintMTimerState *mtimer,
{
uint32_t timebase_freq = mtimer->timebase_freq;
uint64_t next;
uint64_t diff;
- uint64_t rtc = cpu_riscv_read_rtc(mtimer);
+ uint64_t ticks = riscv_aclint_mtimer_get_ticks(mtimer);
/* Compute the relative hartid w.r.t the socket */
hartid = hartid - mtimer->hartid_base;
mtimer->timecmp[hartid] = value;
- if (mtimer->timecmp[hartid] <= rtc) {
+ if (mtimer->timecmp[hartid] <= ticks) {
/*
* If we're setting an MTIMECMP value in the "past",
* immediately raise the timer interrupt
*/
qemu_irq_raise(mtimer->timer_irqs[hartid]);
return;
}
/* otherwise, set up the future timer interrupt */
qemu_irq_lower(mtimer->timer_irqs[hartid]);
- diff = mtimer->timecmp[hartid] - rtc;
+ diff = mtimer->timecmp[hartid] - ticks;
/* back to ns (note args switched in muldiv64) */
uint64_t ns_diff = muldiv64(diff, NANOSECONDS_PER_SECOND, timebase_freq);
/*
* check if ns_diff overflowed and check if the addition would potentially
@@ -149,15 +150,15 @@ static uint64_t riscv_aclint_mtimer_read(void *opaque, hwaddr addr,
"aclint-mtimer: invalid read: %08x", (uint32_t)addr);
return 0;
}
} else if (addr == mtimer->time_base) {
/* time_lo for RV32/RV64 or timecmp for RV64 */
- uint64_t rtc = cpu_riscv_read_rtc(mtimer);
- return (size == 4) ? (rtc & 0xFFFFFFFF) : rtc;
+ uint64_t ticks = riscv_aclint_mtimer_get_ticks(mtimer);
+ return (size == 4) ? (ticks & 0xFFFFFFFF) : ticks;
} else if (addr == mtimer->time_base + 4) {
/* time_hi */
- return (cpu_riscv_read_rtc(mtimer) >> 32) & 0xFFFFFFFF;
+ return (riscv_aclint_mtimer_get_ticks(mtimer) >> 32) & 0xFFFFFFFF;
}
qemu_log_mask(LOG_UNIMP,
"aclint-mtimer: invalid read: %08x", (uint32_t)addr);
return 0;
@@ -206,25 +207,25 @@ static void riscv_aclint_mtimer_write(void *opaque, hwaddr addr,
"aclint-mtimer: invalid timecmp write: %08x",
(uint32_t)addr);
}
return;
} else if (addr == mtimer->time_base || addr == mtimer->time_base + 4) {
- uint64_t rtc_r = cpu_riscv_read_rtc_raw(mtimer->timebase_freq);
- uint64_t rtc = cpu_riscv_read_rtc(mtimer);
+ uint64_t ticks_r = riscv_aclint_mtimer_get_ticks_raw(mtimer->timebase_freq);
+ uint64_t ticks = riscv_aclint_mtimer_get_ticks(mtimer);
if (addr == mtimer->time_base) {
if (size == 4) {
/* time_lo for RV32/RV64 */
- mtimer->time_delta = ((rtc & ~0xFFFFFFFFULL) | value) - rtc_r;
+ mtimer->time_delta = ((ticks & ~0xFFFFFFFFULL) | value) - ticks_r;
} else {
/* time for RV64 */
- mtimer->time_delta = value - rtc_r;
+ mtimer->time_delta = value - ticks_r;
}
} else {
if (size == 4) {
/* time_hi for RV32/RV64 */
- mtimer->time_delta = (value << 32 | (rtc & 0xFFFFFFFF)) - rtc_r;
+ mtimer->time_delta = (value << 32 | (ticks & 0xFFFFFFFF)) - ticks_r;
} else {
qemu_log_mask(LOG_GUEST_ERROR,
"aclint-mtimer: invalid time_hi write: %08x",
(uint32_t)addr);
return;
@@ -395,11 +396,11 @@ DeviceState *riscv_aclint_mtimer_create(hwaddr addr, hwaddr size,
if (!env) {
g_free(cb);
continue;
}
if (provide_rdtime) {
- riscv_cpu_set_rdtime_fn(env, cpu_riscv_read_rtc, dev);
+ riscv_cpu_set_rdtime_fn(env, riscv_aclint_mtimer_get_ticks, dev);
}
cb->s = s;
cb->num = i;
s->timers[i] = timer_new_ns(QEMU_CLOCK_VIRTUAL,
--
2.51.0
^ permalink raw reply related [flat|nested] 21+ messages in thread* Re: [PATCH 3/9] hw/intc/riscv_aclint: rename cpu_riscv_read_rtc to riscv_aclint_mtimer_get_ticks
2025-11-07 10:23 ` [PATCH 3/9] hw/intc/riscv_aclint: rename cpu_riscv_read_rtc to riscv_aclint_mtimer_get_ticks Luc Michel
@ 2025-11-09 13:56 ` Philippe Mathieu-Daudé
0 siblings, 0 replies; 21+ messages in thread
From: Philippe Mathieu-Daudé @ 2025-11-09 13:56 UTC (permalink / raw)
To: Luc Michel, qemu-devel, qemu-riscv
Cc: Palmer Dabbelt, Alistair Francis, Weiwei Li,
Daniel Henrique Barboza, Liu Zhiwei, Francisco Iglesias
On 7/11/25 11:23, Luc Michel wrote:
> For more clarity, rename the cpu_riscv_read_rtc function to
> riscv_aclint_mtimer_get_ticks:
> - The ACLINT is the time source here, not the CPU,
> - This function returns a number of ticks based on the timer
> frequency.
>
> Rename the _raw version of this function as well and the local variables
> storing the result of those function.
>
> Signed-off-by: Luc Michel <luc.michel@amd.com>
> ---
> hw/intc/riscv_aclint.c | 31 ++++++++++++++++---------------
> 1 file changed, 16 insertions(+), 15 deletions(-)
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH 4/9] target/riscv: add the RISCVCPUTimeSrcIf interface
2025-11-07 10:23 [PATCH 0/9] RISC-V CPU time source interface Luc Michel
` (2 preceding siblings ...)
2025-11-07 10:23 ` [PATCH 3/9] hw/intc/riscv_aclint: rename cpu_riscv_read_rtc to riscv_aclint_mtimer_get_ticks Luc Michel
@ 2025-11-07 10:23 ` Luc Michel
2025-11-09 14:02 ` Philippe Mathieu-Daudé
2025-11-07 10:23 ` [PATCH 5/9] hw/intc/riscv_aclint: implement " Luc Michel
` (5 subsequent siblings)
9 siblings, 1 reply; 21+ messages in thread
From: Luc Michel @ 2025-11-07 10:23 UTC (permalink / raw)
To: qemu-devel, qemu-riscv
Cc: Luc Michel, Palmer Dabbelt, Alistair Francis, Weiwei Li,
Daniel Henrique Barboza, Liu Zhiwei, Francisco Iglesias
Add the RISCVCPUTimeSrcIf QOM interface to the RISC-V target. This
interface aims at replacing the existing env->rdtime_fn callback in the
RISC-V CPU env. It allows to query the current number of ticks, and the
tick frequency.
Signed-off-by: Luc Michel <luc.michel@amd.com>
---
target/riscv/cpu-qom.h | 34 ++++++++++++++++++++++++++++++++++
target/riscv/time_helper.h | 16 ++++++++++++++++
target/riscv/time_helper.c | 13 +++++++++++++
3 files changed, 63 insertions(+)
diff --git a/target/riscv/cpu-qom.h b/target/riscv/cpu-qom.h
index 75f4e434085..e5bc23b2ef5 100644
--- a/target/riscv/cpu-qom.h
+++ b/target/riscv/cpu-qom.h
@@ -58,6 +58,40 @@
#define TYPE_RISCV_CPU_XIANGSHAN_KMH RISCV_CPU_TYPE_NAME("xiangshan-kunminghu")
#define TYPE_RISCV_CPU_HOST RISCV_CPU_TYPE_NAME("host")
OBJECT_DECLARE_CPU_TYPE(RISCVCPU, RISCVCPUClass, RISCV_CPU)
+#define TYPE_RISCV_CPU_TIME_SRC_IF "riscv-cpu-time-src-if"
+
+typedef struct RISCVCPUTimeSrcIfClass RISCVCPUTimeSrcIfClass;
+DECLARE_CLASS_CHECKERS(RISCVCPUTimeSrcIfClass, RISCV_CPU_TIME_SRC_IF,
+ TYPE_RISCV_CPU_TIME_SRC_IF)
+#define RISCV_CPU_TIME_SRC_IF(obj) \
+ INTERFACE_CHECK(RISCVCPUTimeSrcIf, (obj), TYPE_RISCV_CPU_TIME_SRC_IF)
+
+typedef struct RISCVCPUTimeSrcIf RISCVCPUTimeSrcIf;
+
+/**
+ * RISCVCPUTimeSrcIf interface
+ *
+ * This interface is used by CPUs implementing the sstc extension. When the CPU
+ * implements this extension, it must have a time source to implement the sstc
+ * timers. Devices implementing this interface provide a monotonic tick counter
+ * and the associated tick frequency so that the CPU code can compute timer
+ * deadlines.
+ */
+struct RISCVCPUTimeSrcIfClass {
+ InterfaceClass parent_class;
+
+ /**
+ * get_ticks: get the current value of the free running counter associated
+ * with this time source.
+ */
+ uint64_t (*get_ticks)(RISCVCPUTimeSrcIf *);
+
+ /**
+ * get_tick_freq: get the tick frequency of this time source.
+ */
+ uint32_t (*get_tick_freq)(RISCVCPUTimeSrcIf *);
+};
+
#endif /* RISCV_CPU_QOM_H */
diff --git a/target/riscv/time_helper.h b/target/riscv/time_helper.h
index af1f634f890..b51fdd96570 100644
--- a/target/riscv/time_helper.h
+++ b/target/riscv/time_helper.h
@@ -26,6 +26,22 @@ void riscv_timer_write_timecmp(CPURISCVState *env, QEMUTimer *timer,
uint64_t timecmp, uint64_t delta,
uint32_t timer_irq);
void riscv_timer_stce_changed(CPURISCVState *env, bool is_m_mode, bool enable);
void riscv_timer_init(RISCVCPU *cpu);
+static inline uint64_t riscv_cpu_time_src_get_ticks(RISCVCPUTimeSrcIf *src)
+{
+ RISCVCPUTimeSrcIfClass *rctsc = RISCV_CPU_TIME_SRC_IF_GET_CLASS(src);
+
+ g_assert(rctsc->get_ticks != NULL);
+ return rctsc->get_ticks(src);
+}
+
+static inline uint32_t riscv_cpu_time_src_get_tick_freq(RISCVCPUTimeSrcIf *src)
+{
+ RISCVCPUTimeSrcIfClass *rctsc = RISCV_CPU_TIME_SRC_IF_GET_CLASS(src);
+
+ g_assert(rctsc->get_tick_freq != NULL);
+ return rctsc->get_tick_freq(src);
+}
+
#endif
diff --git a/target/riscv/time_helper.c b/target/riscv/time_helper.c
index d2ec8a94166..dc0777607ab 100644
--- a/target/riscv/time_helper.c
+++ b/target/riscv/time_helper.c
@@ -198,5 +198,18 @@ void riscv_timer_init(RISCVCPU *cpu)
env->stimecmp = 0;
env->vstimer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &riscv_vstimer_cb, cpu);
env->vstimecmp = 0;
}
+
+static const TypeInfo riscv_cpu_time_src_if_info = {
+ .name = TYPE_RISCV_CPU_TIME_SRC_IF,
+ .parent = TYPE_INTERFACE,
+ .class_size = sizeof(RISCVCPUTimeSrcIfClass),
+};
+
+static void riscv_cpu_time_src_if_register_types(void)
+{
+ type_register_static(&riscv_cpu_time_src_if_info);
+}
+
+type_init(riscv_cpu_time_src_if_register_types)
--
2.51.0
^ permalink raw reply related [flat|nested] 21+ messages in thread* Re: [PATCH 4/9] target/riscv: add the RISCVCPUTimeSrcIf interface
2025-11-07 10:23 ` [PATCH 4/9] target/riscv: add the RISCVCPUTimeSrcIf interface Luc Michel
@ 2025-11-09 14:02 ` Philippe Mathieu-Daudé
0 siblings, 0 replies; 21+ messages in thread
From: Philippe Mathieu-Daudé @ 2025-11-09 14:02 UTC (permalink / raw)
To: Luc Michel, qemu-devel, qemu-riscv
Cc: Palmer Dabbelt, Alistair Francis, Weiwei Li,
Daniel Henrique Barboza, Liu Zhiwei, Francisco Iglesias
On 7/11/25 11:23, Luc Michel wrote:
> Add the RISCVCPUTimeSrcIf QOM interface to the RISC-V target. This
> interface aims at replacing the existing env->rdtime_fn callback in the
> RISC-V CPU env. It allows to query the current number of ticks, and the
> tick frequency.
>
> Signed-off-by: Luc Michel <luc.michel@amd.com>
> ---
> target/riscv/cpu-qom.h | 34 ++++++++++++++++++++++++++++++++++
> target/riscv/time_helper.h | 16 ++++++++++++++++
> target/riscv/time_helper.c | 13 +++++++++++++
> 3 files changed, 63 insertions(+)
>
> diff --git a/target/riscv/cpu-qom.h b/target/riscv/cpu-qom.h
> index 75f4e434085..e5bc23b2ef5 100644
> --- a/target/riscv/cpu-qom.h
> +++ b/target/riscv/cpu-qom.h
> @@ -58,6 +58,40 @@
> #define TYPE_RISCV_CPU_XIANGSHAN_KMH RISCV_CPU_TYPE_NAME("xiangshan-kunminghu")
> #define TYPE_RISCV_CPU_HOST RISCV_CPU_TYPE_NAME("host")
>
> OBJECT_DECLARE_CPU_TYPE(RISCVCPU, RISCVCPUClass, RISCV_CPU)
>
> +#define TYPE_RISCV_CPU_TIME_SRC_IF "riscv-cpu-time-src-if"
> +
> +typedef struct RISCVCPUTimeSrcIfClass RISCVCPUTimeSrcIfClass;
> +DECLARE_CLASS_CHECKERS(RISCVCPUTimeSrcIfClass, RISCV_CPU_TIME_SRC_IF,
> + TYPE_RISCV_CPU_TIME_SRC_IF)
> +#define RISCV_CPU_TIME_SRC_IF(obj) \
> + INTERFACE_CHECK(RISCVCPUTimeSrcIf, (obj), TYPE_RISCV_CPU_TIME_SRC_IF)
> +
> +typedef struct RISCVCPUTimeSrcIf RISCVCPUTimeSrcIf;
> +
> +/**
> + * RISCVCPUTimeSrcIf interface
> + *
> + * This interface is used by CPUs implementing the sstc extension. When the CPU
> + * implements this extension, it must have a time source to implement the sstc
> + * timers. Devices implementing this interface provide a monotonic tick counter
> + * and the associated tick frequency so that the CPU code can compute timer
> + * deadlines.
> + */
> +struct RISCVCPUTimeSrcIfClass {
> + InterfaceClass parent_class;
> +
> + /**
> + * get_ticks: get the current value of the free running counter associated
> + * with this time source.
> + */
> + uint64_t (*get_ticks)(RISCVCPUTimeSrcIf *);
> +
> + /**
> + * get_tick_freq: get the tick frequency of this time source.
> + */
> + uint32_t (*get_tick_freq)(RISCVCPUTimeSrcIf *);
> +};
Thanks for the documentation :)
> diff --git a/target/riscv/time_helper.h b/target/riscv/time_helper.h
> index af1f634f890..b51fdd96570 100644
> --- a/target/riscv/time_helper.h
> +++ b/target/riscv/time_helper.h
> @@ -26,6 +26,22 @@ void riscv_timer_write_timecmp(CPURISCVState *env, QEMUTimer *timer,
> uint64_t timecmp, uint64_t delta,
> uint32_t timer_irq);
> void riscv_timer_stce_changed(CPURISCVState *env, bool is_m_mode, bool enable);
> void riscv_timer_init(RISCVCPU *cpu);
>
> +static inline uint64_t riscv_cpu_time_src_get_ticks(RISCVCPUTimeSrcIf *src)
> +{
> + RISCVCPUTimeSrcIfClass *rctsc = RISCV_CPU_TIME_SRC_IF_GET_CLASS(src);
> +
> + g_assert(rctsc->get_ticks != NULL);
> + return rctsc->get_ticks(src);
> +}
> +
> +static inline uint32_t riscv_cpu_time_src_get_tick_freq(RISCVCPUTimeSrcIf *src)
> +{
> + RISCVCPUTimeSrcIfClass *rctsc = RISCV_CPU_TIME_SRC_IF_GET_CLASS(src);
> +
> + g_assert(rctsc->get_tick_freq != NULL);
> + return rctsc->get_tick_freq(src);
> +}
Why inlining these functions? Otherwise,
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH 5/9] hw/intc/riscv_aclint: implement the RISCVCPUTimeSrcIf interface
2025-11-07 10:23 [PATCH 0/9] RISC-V CPU time source interface Luc Michel
` (3 preceding siblings ...)
2025-11-07 10:23 ` [PATCH 4/9] target/riscv: add the RISCVCPUTimeSrcIf interface Luc Michel
@ 2025-11-07 10:23 ` Luc Michel
2025-11-09 14:01 ` Philippe Mathieu-Daudé
2025-11-07 10:23 ` [PATCH 6/9] target/riscv: replace env->rdtime_fn with a time source Luc Michel
` (4 subsequent siblings)
9 siblings, 1 reply; 21+ messages in thread
From: Luc Michel @ 2025-11-07 10:23 UTC (permalink / raw)
To: qemu-devel, qemu-riscv
Cc: Luc Michel, Palmer Dabbelt, Alistair Francis, Weiwei Li,
Daniel Henrique Barboza, Liu Zhiwei, Francisco Iglesias
Implement the RISCVCPUTimeSrcIf QOM interface in the ACLINT mtimer device
model.
Signed-off-by: Luc Michel <luc.michel@amd.com>
---
hw/intc/riscv_aclint.c | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/hw/intc/riscv_aclint.c b/hw/intc/riscv_aclint.c
index 95398e48821..4a4449d9d2f 100644
--- a/hw/intc/riscv_aclint.c
+++ b/hw/intc/riscv_aclint.c
@@ -325,10 +325,25 @@ static void riscv_aclint_mtimer_reset_enter(Object *obj, ResetType type)
* Pending mtime interrupts will also be cleared at the same time.
*/
riscv_aclint_mtimer_write(mtimer, mtimer->time_base, 0, 8);
}
+static uint64_t riscv_aclint_mtimer_time_src_get_ticks(RISCVCPUTimeSrcIf *iface)
+{
+ RISCVAclintMTimerState *mtimer = RISCV_ACLINT_MTIMER(iface);
+
+ return riscv_aclint_mtimer_get_ticks(mtimer);
+}
+
+static uint32_t riscv_aclint_mtimer_time_src_get_tick_freq(RISCVCPUTimeSrcIf *iface)
+{
+ RISCVAclintMTimerState *mtimer = RISCV_ACLINT_MTIMER(iface);
+
+ return mtimer->timebase_freq;
+}
+
+
static const VMStateDescription vmstate_riscv_mtimer = {
.name = "riscv_mtimer",
.version_id = 3,
.minimum_version_id = 3,
.fields = (const VMStateField[]) {
@@ -344,22 +359,29 @@ static const VMStateDescription vmstate_riscv_mtimer = {
static void riscv_aclint_mtimer_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
+ RISCVCPUTimeSrcIfClass *rctsc = RISCV_CPU_TIME_SRC_IF_CLASS(klass);
dc->realize = riscv_aclint_mtimer_realize;
device_class_set_props(dc, riscv_aclint_mtimer_properties);
rc->phases.enter = riscv_aclint_mtimer_reset_enter;
dc->vmsd = &vmstate_riscv_mtimer;
+ rctsc->get_ticks = riscv_aclint_mtimer_time_src_get_ticks;
+ rctsc->get_tick_freq = riscv_aclint_mtimer_time_src_get_tick_freq;
}
static const TypeInfo riscv_aclint_mtimer_info = {
.name = TYPE_RISCV_ACLINT_MTIMER,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(RISCVAclintMTimerState),
.class_init = riscv_aclint_mtimer_class_init,
+ .interfaces = (const InterfaceInfo []) {
+ { TYPE_RISCV_CPU_TIME_SRC_IF },
+ { },
+ },
};
/*
* Create ACLINT MTIMER device.
*/
--
2.51.0
^ permalink raw reply related [flat|nested] 21+ messages in thread* Re: [PATCH 5/9] hw/intc/riscv_aclint: implement the RISCVCPUTimeSrcIf interface
2025-11-07 10:23 ` [PATCH 5/9] hw/intc/riscv_aclint: implement " Luc Michel
@ 2025-11-09 14:01 ` Philippe Mathieu-Daudé
0 siblings, 0 replies; 21+ messages in thread
From: Philippe Mathieu-Daudé @ 2025-11-09 14:01 UTC (permalink / raw)
To: Luc Michel, qemu-devel, qemu-riscv
Cc: Palmer Dabbelt, Alistair Francis, Weiwei Li,
Daniel Henrique Barboza, Liu Zhiwei, Francisco Iglesias
On 7/11/25 11:23, Luc Michel wrote:
> Implement the RISCVCPUTimeSrcIf QOM interface in the ACLINT mtimer device
> model.
>
> Signed-off-by: Luc Michel <luc.michel@amd.com>
> ---
> hw/intc/riscv_aclint.c | 22 ++++++++++++++++++++++
> 1 file changed, 22 insertions(+)
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH 6/9] target/riscv: replace env->rdtime_fn with a time source
2025-11-07 10:23 [PATCH 0/9] RISC-V CPU time source interface Luc Michel
` (4 preceding siblings ...)
2025-11-07 10:23 ` [PATCH 5/9] hw/intc/riscv_aclint: implement " Luc Michel
@ 2025-11-07 10:23 ` Luc Michel
2025-11-09 13:59 ` Philippe Mathieu-Daudé
2025-11-07 10:23 ` [PATCH 7/9] hw/intc/riscv_aclint: riscv_aclint_mtimer_get_ticks: get rid of void* argument Luc Michel
` (3 subsequent siblings)
9 siblings, 1 reply; 21+ messages in thread
From: Luc Michel @ 2025-11-07 10:23 UTC (permalink / raw)
To: qemu-devel, qemu-riscv
Cc: Luc Michel, Palmer Dabbelt, Alistair Francis, Weiwei Li,
Daniel Henrique Barboza, Liu Zhiwei, Francisco Iglesias
Replace the env->rdtime_fn function pointer with an instance of the
RISCVCPUTimeSrcIf QOM interface.
This allows to remove the dependency on the ACLINT in the
riscv_timer_write_timecmp function:
- This dependency was buggy because env->rdtime_fn_arg was an opaque
pointer and was converted in riscv_timer_write_timecmp to a ACLINT
without dynamic type check.
- This will allow to have time sources provided by other devices than
an ACLINT.
Signed-off-by: Luc Michel <luc.michel@amd.com>
---
target/riscv/cpu.h | 8 +++-----
hw/intc/riscv_aclint.c | 2 +-
target/riscv/cpu_helper.c | 7 -------
target/riscv/csr.c | 24 ++++++++++++------------
target/riscv/time_helper.c | 15 +++++++++------
5 files changed, 25 insertions(+), 31 deletions(-)
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 36e7f100374..368b9e2532d 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -458,13 +458,12 @@ struct CPUArchState {
struct CPUWatchpoint *cpu_watchpoint[RV_MAX_TRIGGERS];
QEMUTimer *itrigger_timer[RV_MAX_TRIGGERS];
int64_t last_icount;
bool itrigger_enabled;
- /* machine specific rdtime callback */
- uint64_t (*rdtime_fn)(void *);
- void *rdtime_fn_arg;
+ /* machine specific time source interface */
+ RISCVCPUTimeSrcIf *time_src;
/* machine specific AIA ireg read-modify-write callback */
#define AIA_MAKE_IREG(__isel, __priv, __virt, __vgein, __xlen) \
((((__xlen) & 0xff) << 24) | \
(((__vgein) & 0x3f) << 20) | \
@@ -642,12 +641,11 @@ int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint64_t interrupts);
uint64_t riscv_cpu_update_mip(CPURISCVState *env, uint64_t mask,
uint64_t value);
void riscv_cpu_set_rnmi(RISCVCPU *cpu, uint32_t irq, bool level);
void riscv_cpu_interrupt(CPURISCVState *env);
#define BOOL_TO_MASK(x) (-!!(x)) /* helper for riscv_cpu_update_mip value */
-void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(void *),
- void *arg);
+void riscv_cpu_set_time_src(CPURISCVState *env, RISCVCPUTimeSrcIf *src);
void riscv_cpu_set_aia_ireg_rmw_fn(CPURISCVState *env, uint32_t priv,
int (*rmw_fn)(void *arg,
target_ulong reg,
target_ulong *val,
target_ulong new_val,
diff --git a/hw/intc/riscv_aclint.c b/hw/intc/riscv_aclint.c
index 4a4449d9d2f..8d001a5eb20 100644
--- a/hw/intc/riscv_aclint.c
+++ b/hw/intc/riscv_aclint.c
@@ -418,11 +418,11 @@ DeviceState *riscv_aclint_mtimer_create(hwaddr addr, hwaddr size,
if (!env) {
g_free(cb);
continue;
}
if (provide_rdtime) {
- riscv_cpu_set_rdtime_fn(env, riscv_aclint_mtimer_get_ticks, dev);
+ riscv_cpu_set_time_src(env, RISCV_CPU_TIME_SRC_IF(dev));
}
cb->s = s;
cb->num = i;
s->timers[i] = timer_new_ns(QEMU_CLOCK_VIRTUAL,
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index c4fb68b5de8..f642ec80b31 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -757,17 +757,10 @@ uint64_t riscv_cpu_update_mip(CPURISCVState *env, uint64_t mask, uint64_t value)
riscv_cpu_interrupt(env);
return old;
}
-void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(void *),
- void *arg)
-{
- env->rdtime_fn = fn;
- env->rdtime_fn_arg = arg;
-}
-
void riscv_cpu_set_aia_ireg_rmw_fn(CPURISCVState *env, uint32_t priv,
int (*rmw_fn)(void *arg,
target_ulong reg,
target_ulong *val,
target_ulong new_val,
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 5c91658c3dc..583f646460c 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -572,11 +572,11 @@ static RISCVException sstateen(CPURISCVState *env, int csrno)
static RISCVException sstc(CPURISCVState *env, int csrno)
{
bool hmode_check = false;
- if (!riscv_cpu_cfg(env)->ext_sstc || !env->rdtime_fn) {
+ if (!riscv_cpu_cfg(env)->ext_sstc || !env->time_src) {
return RISCV_EXCP_ILLEGAL_INST;
}
if ((csrno == CSR_VSTIMECMP) || (csrno == CSR_VSTIMECMPH)) {
hmode_check = true;
@@ -1634,28 +1634,28 @@ static RISCVException read_scountovf(CPURISCVState *env, int csrno,
static RISCVException read_time(CPURISCVState *env, int csrno,
target_ulong *val)
{
uint64_t delta = env->virt_enabled ? env->htimedelta : 0;
- if (!env->rdtime_fn) {
+ if (!env->time_src) {
return RISCV_EXCP_ILLEGAL_INST;
}
- *val = env->rdtime_fn(env->rdtime_fn_arg) + delta;
+ *val = riscv_cpu_time_src_get_ticks(env->time_src) + delta;
return RISCV_EXCP_NONE;
}
static RISCVException read_timeh(CPURISCVState *env, int csrno,
target_ulong *val)
{
uint64_t delta = env->virt_enabled ? env->htimedelta : 0;
- if (!env->rdtime_fn) {
+ if (!env->time_src) {
return RISCV_EXCP_ILLEGAL_INST;
}
- *val = (env->rdtime_fn(env->rdtime_fn_arg) + delta) >> 32;
+ *val = (riscv_cpu_time_src_get_ticks(env->time_src) + delta) >> 32;
return RISCV_EXCP_NONE;
}
static RISCVException read_vstimecmp(CPURISCVState *env, int csrno,
target_ulong *val)
@@ -4965,60 +4965,60 @@ static RISCVException write_hgatp(CPURISCVState *env, int csrno,
}
static RISCVException read_htimedelta(CPURISCVState *env, int csrno,
target_ulong *val)
{
- if (!env->rdtime_fn) {
+ if (!env->time_src) {
return RISCV_EXCP_ILLEGAL_INST;
}
*val = env->htimedelta;
return RISCV_EXCP_NONE;
}
static RISCVException write_htimedelta(CPURISCVState *env, int csrno,
target_ulong val, uintptr_t ra)
{
- if (!env->rdtime_fn) {
+ if (!env->time_src) {
return RISCV_EXCP_ILLEGAL_INST;
}
if (riscv_cpu_mxl(env) == MXL_RV32) {
env->htimedelta = deposit64(env->htimedelta, 0, 32, (uint64_t)val);
} else {
env->htimedelta = val;
}
- if (riscv_cpu_cfg(env)->ext_sstc && env->rdtime_fn) {
+ if (riscv_cpu_cfg(env)->ext_sstc) {
riscv_timer_write_timecmp(env, env->vstimer, env->vstimecmp,
env->htimedelta, MIP_VSTIP);
}
return RISCV_EXCP_NONE;
}
static RISCVException read_htimedeltah(CPURISCVState *env, int csrno,
target_ulong *val)
{
- if (!env->rdtime_fn) {
+ if (!env->time_src) {
return RISCV_EXCP_ILLEGAL_INST;
}
*val = env->htimedelta >> 32;
return RISCV_EXCP_NONE;
}
static RISCVException write_htimedeltah(CPURISCVState *env, int csrno,
target_ulong val, uintptr_t ra)
{
- if (!env->rdtime_fn) {
+ if (!env->time_src) {
return RISCV_EXCP_ILLEGAL_INST;
}
env->htimedelta = deposit64(env->htimedelta, 32, 32, (uint64_t)val);
- if (riscv_cpu_cfg(env)->ext_sstc && env->rdtime_fn) {
+ if (riscv_cpu_cfg(env)->ext_sstc) {
riscv_timer_write_timecmp(env, env->vstimer, env->vstimecmp,
env->htimedelta, MIP_VSTIP);
}
return RISCV_EXCP_NONE;
@@ -5825,11 +5825,11 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
[CSR_CYCLEH] = { "cycleh", ctr32, read_hpmcounterh },
[CSR_INSTRETH] = { "instreth", ctr32, read_hpmcounterh },
/*
* In privileged mode, the monitor will have to emulate TIME CSRs only if
- * rdtime callback is not provided by machine/platform emulation.
+ * CPU time source interface is not provided by machine/platform emulation.
*/
[CSR_TIME] = { "time", ctr, read_time },
[CSR_TIMEH] = { "timeh", ctr32, read_timeh },
/* Crypto Extension */
diff --git a/target/riscv/time_helper.c b/target/riscv/time_helper.c
index dc0777607ab..7b493b7a233 100644
--- a/target/riscv/time_helper.c
+++ b/target/riscv/time_helper.c
@@ -17,11 +17,10 @@
*/
#include "qemu/osdep.h"
#include "cpu_bits.h"
#include "time_helper.h"
-#include "hw/intc/riscv_aclint.h"
static void riscv_vstimer_cb(void *opaque)
{
RISCVCPU *cpu = opaque;
CPURISCVState *env = &cpu->env;
@@ -42,28 +41,27 @@ static void riscv_stimer_cb(void *opaque)
void riscv_timer_write_timecmp(CPURISCVState *env, QEMUTimer *timer,
uint64_t timecmp, uint64_t delta,
uint32_t timer_irq)
{
uint64_t diff, ns_diff, next;
- RISCVAclintMTimerState *mtimer = env->rdtime_fn_arg;
uint32_t timebase_freq;
uint64_t rtc_r;
- if (!riscv_cpu_cfg(env)->ext_sstc || !env->rdtime_fn ||
- !env->rdtime_fn_arg || !get_field(env->menvcfg, MENVCFG_STCE)) {
+ if (!riscv_cpu_cfg(env)->ext_sstc || !env->time_src ||
+ !get_field(env->menvcfg, MENVCFG_STCE)) {
/* S/VS Timer IRQ depends on sstc extension, rdtime_fn(), and STCE. */
return;
}
if (timer_irq == MIP_VSTIP &&
(!riscv_has_ext(env, RVH) || !get_field(env->henvcfg, HENVCFG_STCE))) {
/* VS Timer IRQ also depends on RVH and henvcfg.STCE. */
return;
}
- timebase_freq = mtimer->timebase_freq;
- rtc_r = env->rdtime_fn(env->rdtime_fn_arg) + delta;
+ timebase_freq = riscv_cpu_time_src_get_tick_freq(env->time_src);
+ rtc_r = riscv_cpu_time_src_get_ticks(env->time_src) + delta;
if (timecmp <= rtc_r) {
/*
* If we're setting an stimecmp value in the "past",
* immediately raise the timer interrupt
@@ -199,10 +197,15 @@ void riscv_timer_init(RISCVCPU *cpu)
env->vstimer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &riscv_vstimer_cb, cpu);
env->vstimecmp = 0;
}
+void riscv_cpu_set_time_src(CPURISCVState *env, RISCVCPUTimeSrcIf *src)
+{
+ env->time_src = src;
+}
+
static const TypeInfo riscv_cpu_time_src_if_info = {
.name = TYPE_RISCV_CPU_TIME_SRC_IF,
.parent = TYPE_INTERFACE,
.class_size = sizeof(RISCVCPUTimeSrcIfClass),
};
--
2.51.0
^ permalink raw reply related [flat|nested] 21+ messages in thread* Re: [PATCH 6/9] target/riscv: replace env->rdtime_fn with a time source
2025-11-07 10:23 ` [PATCH 6/9] target/riscv: replace env->rdtime_fn with a time source Luc Michel
@ 2025-11-09 13:59 ` Philippe Mathieu-Daudé
0 siblings, 0 replies; 21+ messages in thread
From: Philippe Mathieu-Daudé @ 2025-11-09 13:59 UTC (permalink / raw)
To: Luc Michel, qemu-devel, qemu-riscv
Cc: Palmer Dabbelt, Alistair Francis, Weiwei Li,
Daniel Henrique Barboza, Liu Zhiwei, Francisco Iglesias
On 7/11/25 11:23, Luc Michel wrote:
> Replace the env->rdtime_fn function pointer with an instance of the
> RISCVCPUTimeSrcIf QOM interface.
>
> This allows to remove the dependency on the ACLINT in the
> riscv_timer_write_timecmp function:
> - This dependency was buggy because env->rdtime_fn_arg was an opaque
> pointer and was converted in riscv_timer_write_timecmp to a ACLINT
> without dynamic type check.
> - This will allow to have time sources provided by other devices than
> an ACLINT.
>
> Signed-off-by: Luc Michel <luc.michel@amd.com>
> ---
> target/riscv/cpu.h | 8 +++-----
> hw/intc/riscv_aclint.c | 2 +-
> target/riscv/cpu_helper.c | 7 -------
> target/riscv/csr.c | 24 ++++++++++++------------
> target/riscv/time_helper.c | 15 +++++++++------
> 5 files changed, 25 insertions(+), 31 deletions(-)
> +void riscv_cpu_set_time_src(CPURISCVState *env, RISCVCPUTimeSrcIf *src)
> +{
> + env->time_src = src;
Worth asserting time_src is NULL? Regardless, good cleanup:
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
> +}
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH 7/9] hw/intc/riscv_aclint: riscv_aclint_mtimer_get_ticks: get rid of void* argument
2025-11-07 10:23 [PATCH 0/9] RISC-V CPU time source interface Luc Michel
` (5 preceding siblings ...)
2025-11-07 10:23 ` [PATCH 6/9] target/riscv: replace env->rdtime_fn with a time source Luc Michel
@ 2025-11-07 10:23 ` Luc Michel
2025-11-09 13:59 ` Philippe Mathieu-Daudé
2025-11-07 10:23 ` [PATCH 8/9] target/riscv: RISCVCPUTimeSrcIf: add register_time_change_notifier Luc Michel
` (2 subsequent siblings)
9 siblings, 1 reply; 21+ messages in thread
From: Luc Michel @ 2025-11-07 10:23 UTC (permalink / raw)
To: qemu-devel, qemu-riscv
Cc: Luc Michel, Palmer Dabbelt, Alistair Francis, Weiwei Li,
Daniel Henrique Barboza, Liu Zhiwei, Francisco Iglesias
Now that the riscv_aclint_mtimer_get_ticks is only used internally,
replace its void* argument with the proper RISCVAclintMTimerState type.
Signed-off-by: Luc Michel <luc.michel@amd.com>
---
hw/intc/riscv_aclint.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/hw/intc/riscv_aclint.c b/hw/intc/riscv_aclint.c
index 8d001a5eb20..014b733d72f 100644
--- a/hw/intc/riscv_aclint.c
+++ b/hw/intc/riscv_aclint.c
@@ -44,13 +44,12 @@ static uint64_t riscv_aclint_mtimer_get_ticks_raw(uint32_t timebase_freq)
{
return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
timebase_freq, NANOSECONDS_PER_SECOND);
}
-static uint64_t riscv_aclint_mtimer_get_ticks(void *opaque)
+static uint64_t riscv_aclint_mtimer_get_ticks(RISCVAclintMTimerState *mtimer)
{
- RISCVAclintMTimerState *mtimer = opaque;
return riscv_aclint_mtimer_get_ticks_raw(mtimer->timebase_freq) +
mtimer->time_delta;
}
/*
--
2.51.0
^ permalink raw reply related [flat|nested] 21+ messages in thread* Re: [PATCH 7/9] hw/intc/riscv_aclint: riscv_aclint_mtimer_get_ticks: get rid of void* argument
2025-11-07 10:23 ` [PATCH 7/9] hw/intc/riscv_aclint: riscv_aclint_mtimer_get_ticks: get rid of void* argument Luc Michel
@ 2025-11-09 13:59 ` Philippe Mathieu-Daudé
0 siblings, 0 replies; 21+ messages in thread
From: Philippe Mathieu-Daudé @ 2025-11-09 13:59 UTC (permalink / raw)
To: Luc Michel, qemu-devel, qemu-riscv
Cc: Palmer Dabbelt, Alistair Francis, Weiwei Li,
Daniel Henrique Barboza, Liu Zhiwei, Francisco Iglesias
On 7/11/25 11:23, Luc Michel wrote:
> Now that the riscv_aclint_mtimer_get_ticks is only used internally,
> replace its void* argument with the proper RISCVAclintMTimerState type.
>
> Signed-off-by: Luc Michel <luc.michel@amd.com>
> ---
> hw/intc/riscv_aclint.c | 3 +--
> 1 file changed, 1 insertion(+), 2 deletions(-)
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH 8/9] target/riscv: RISCVCPUTimeSrcIf: add register_time_change_notifier
2025-11-07 10:23 [PATCH 0/9] RISC-V CPU time source interface Luc Michel
` (6 preceding siblings ...)
2025-11-07 10:23 ` [PATCH 7/9] hw/intc/riscv_aclint: riscv_aclint_mtimer_get_ticks: get rid of void* argument Luc Michel
@ 2025-11-07 10:23 ` Luc Michel
2025-11-20 17:20 ` Philippe Mathieu-Daudé
2025-11-07 10:23 ` [PATCH 9/9] hw/intc/riscv_aclint: implement the register_time_change_notifier method Luc Michel
2025-11-14 9:25 ` [PATCH 0/9] RISC-V CPU time source interface Luc Michel
9 siblings, 1 reply; 21+ messages in thread
From: Luc Michel @ 2025-11-07 10:23 UTC (permalink / raw)
To: qemu-devel, qemu-riscv
Cc: Luc Michel, Palmer Dabbelt, Alistair Francis, Weiwei Li,
Daniel Henrique Barboza, Liu Zhiwei, Francisco Iglesias
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
^ permalink raw reply related [flat|nested] 21+ messages in thread* Re: [PATCH 8/9] target/riscv: RISCVCPUTimeSrcIf: add register_time_change_notifier
2025-11-07 10:23 ` [PATCH 8/9] target/riscv: RISCVCPUTimeSrcIf: add register_time_change_notifier Luc Michel
@ 2025-11-20 17:20 ` Philippe Mathieu-Daudé
0 siblings, 0 replies; 21+ messages in thread
From: Philippe Mathieu-Daudé @ 2025-11-20 17:20 UTC (permalink / raw)
To: Luc Michel, qemu-devel, qemu-riscv
Cc: Palmer Dabbelt, Alistair Francis, Weiwei Li,
Daniel Henrique Barboza, Liu Zhiwei, Francisco Iglesias
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>
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH 9/9] hw/intc/riscv_aclint: implement the register_time_change_notifier method
2025-11-07 10:23 [PATCH 0/9] RISC-V CPU time source interface Luc Michel
` (7 preceding siblings ...)
2025-11-07 10:23 ` [PATCH 8/9] target/riscv: RISCVCPUTimeSrcIf: add register_time_change_notifier Luc Michel
@ 2025-11-07 10:23 ` Luc Michel
2025-11-20 17:22 ` Philippe Mathieu-Daudé
2025-11-14 9:25 ` [PATCH 0/9] RISC-V CPU time source interface Luc Michel
9 siblings, 1 reply; 21+ messages in thread
From: Luc Michel @ 2025-11-07 10:23 UTC (permalink / raw)
To: qemu-devel, qemu-riscv
Cc: Luc Michel, Palmer Dabbelt, Alistair Francis, Weiwei Li,
Daniel Henrique Barboza, Liu Zhiwei, Francisco Iglesias
Implement the register_time_change_notifier method of the
RISCVCPUTimeSrcIf interface in the ACLINT. Keep a notifier list and
notify it upon `time' register modification. This effectively replaces
the explicit calls to the internal riscv_timer_write_timecmp CPU
functions as this is now done by the corresponding CPU notifier.
Signed-off-by: Luc Michel <luc.michel@amd.com>
---
include/hw/intc/riscv_aclint.h | 1 +
hw/intc/riscv_aclint.c | 16 +++++++++++-----
2 files changed, 12 insertions(+), 5 deletions(-)
diff --git a/include/hw/intc/riscv_aclint.h b/include/hw/intc/riscv_aclint.h
index 4b7406eec00..3451aa1786b 100644
--- a/include/hw/intc/riscv_aclint.h
+++ b/include/hw/intc/riscv_aclint.h
@@ -32,10 +32,11 @@ typedef struct RISCVAclintMTimerState {
/*< private >*/
SysBusDevice parent_obj;
uint64_t time_delta;
uint64_t *timecmp;
QEMUTimer **timers;
+ NotifierList time_change_notifiers;
/*< public >*/
MemoryRegion mmio;
uint32_t hartid_base;
uint32_t num_harts;
diff --git a/hw/intc/riscv_aclint.c b/hw/intc/riscv_aclint.c
index 014b733d72f..f5e120cc853 100644
--- a/hw/intc/riscv_aclint.c
+++ b/hw/intc/riscv_aclint.c
@@ -26,11 +26,10 @@
#include "qemu/error-report.h"
#include "qemu/log.h"
#include "qemu/module.h"
#include "hw/sysbus.h"
#include "target/riscv/cpu.h"
-#include "target/riscv/time_helper.h"
#include "hw/qdev-properties.h"
#include "hw/intc/riscv_aclint.h"
#include "qemu/timer.h"
#include "hw/irq.h"
#include "migration/vmstate.h"
@@ -239,15 +238,13 @@ static void riscv_aclint_mtimer_write(void *opaque, hwaddr addr,
continue;
}
riscv_aclint_mtimer_write_timecmp(mtimer, RISCV_CPU(cpu),
mtimer->hartid_base + i,
mtimer->timecmp[i]);
- 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);
-
}
+
+ notifier_list_notify(&mtimer->time_change_notifiers, NULL);
return;
}
qemu_log_mask(LOG_UNIMP,
"aclint-mtimer: invalid write: %08x", (uint32_t)addr);
@@ -284,10 +281,11 @@ static const Property riscv_aclint_mtimer_properties[] = {
static void riscv_aclint_mtimer_realize(DeviceState *dev, Error **errp)
{
RISCVAclintMTimerState *s = RISCV_ACLINT_MTIMER(dev);
int i;
+ notifier_list_init(&s->time_change_notifiers);
memory_region_init_io(&s->mmio, OBJECT(dev), &riscv_aclint_mtimer_ops,
s, TYPE_RISCV_ACLINT_MTIMER, s->aperture_size);
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
s->timer_irqs = g_new(qemu_irq, s->num_harts);
@@ -338,10 +336,17 @@ static uint32_t riscv_aclint_mtimer_time_src_get_tick_freq(RISCVCPUTimeSrcIf *if
RISCVAclintMTimerState *mtimer = RISCV_ACLINT_MTIMER(iface);
return mtimer->timebase_freq;
}
+static void mtimer_time_src_register_change_notifier(RISCVCPUTimeSrcIf *iface,
+ Notifier *notifier)
+{
+ RISCVAclintMTimerState *mtimer = RISCV_ACLINT_MTIMER(iface);
+
+ notifier_list_add(&mtimer->time_change_notifiers, notifier);
+}
static const VMStateDescription vmstate_riscv_mtimer = {
.name = "riscv_mtimer",
.version_id = 3,
.minimum_version_id = 3,
@@ -366,10 +371,11 @@ static void riscv_aclint_mtimer_class_init(ObjectClass *klass, const void *data)
device_class_set_props(dc, riscv_aclint_mtimer_properties);
rc->phases.enter = riscv_aclint_mtimer_reset_enter;
dc->vmsd = &vmstate_riscv_mtimer;
rctsc->get_ticks = riscv_aclint_mtimer_time_src_get_ticks;
rctsc->get_tick_freq = riscv_aclint_mtimer_time_src_get_tick_freq;
+ rctsc->register_time_change_notifier = mtimer_time_src_register_change_notifier;
}
static const TypeInfo riscv_aclint_mtimer_info = {
.name = TYPE_RISCV_ACLINT_MTIMER,
.parent = TYPE_SYS_BUS_DEVICE,
--
2.51.0
^ permalink raw reply related [flat|nested] 21+ messages in thread* Re: [PATCH 9/9] hw/intc/riscv_aclint: implement the register_time_change_notifier method
2025-11-07 10:23 ` [PATCH 9/9] hw/intc/riscv_aclint: implement the register_time_change_notifier method Luc Michel
@ 2025-11-20 17:22 ` Philippe Mathieu-Daudé
0 siblings, 0 replies; 21+ messages in thread
From: Philippe Mathieu-Daudé @ 2025-11-20 17:22 UTC (permalink / raw)
To: Luc Michel, qemu-devel, qemu-riscv
Cc: Palmer Dabbelt, Alistair Francis, Weiwei Li,
Daniel Henrique Barboza, Liu Zhiwei, Francisco Iglesias
On 7/11/25 11:23, Luc Michel wrote:
> Implement the register_time_change_notifier method of the
> RISCVCPUTimeSrcIf interface in the ACLINT. Keep a notifier list and
> notify it upon `time' register modification. This effectively replaces
> the explicit calls to the internal riscv_timer_write_timecmp CPU
> functions as this is now done by the corresponding CPU notifier.
>
> Signed-off-by: Luc Michel <luc.michel@amd.com>
> ---
> include/hw/intc/riscv_aclint.h | 1 +
> hw/intc/riscv_aclint.c | 16 +++++++++++-----
> 2 files changed, 12 insertions(+), 5 deletions(-)
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH 0/9] RISC-V CPU time source interface
2025-11-07 10:23 [PATCH 0/9] RISC-V CPU time source interface Luc Michel
` (8 preceding siblings ...)
2025-11-07 10:23 ` [PATCH 9/9] hw/intc/riscv_aclint: implement the register_time_change_notifier method Luc Michel
@ 2025-11-14 9:25 ` Luc Michel
2025-11-20 17:16 ` Philippe Mathieu-Daudé
9 siblings, 1 reply; 21+ messages in thread
From: Luc Michel @ 2025-11-14 9:25 UTC (permalink / raw)
To: qemu-devel, qemu-riscv
Cc: Palmer Dabbelt, Alistair Francis, Weiwei Li,
Daniel Henrique Barboza, Liu Zhiwei, Francisco Iglesias
On 11:23 Fri 07 Nov , Luc Michel wrote:
> Hello,
>
> By working locally on a RISC-V CPU with the sstc extension, I noticed
> that the sstc code (the `riscv_timer_write_timecmp' function) was
> implicitly assuming that the object behind the env->rdtime_fn callback
> was a ACLINT. This is not a correct assumption from the point of view of
> the riscv_cpu_set_rdtime_fn function API since env->rdtime_fn_arg is a
> `void *' and is not required to be a ACLINT.
>
> I reworked this and ended up with this series. It introduces the
> RISCVCPUTimeSrcIf interface to replace the env->rdtime_fn callback and
> break this dependency. This interface provides a mean to retrieve the
> number of ticks (same as the rdtime_fn callback), and the tick frequency
> that `riscv_timer_write_timecmp' needs.
>
> This will effectively allow other platforms with CPUs and the sstc
> extension but no ACLINT to provide their own time source. For now only
> the ACLINT implements this interface.
>
> The last two patches enhance the interface with a tick change notifier
> registering mechanism. This allows the time source user (the CPU) to get
> notified when the time source tick counter gets asynchronously modified
> (reset to 0, ...), i.e., when the time register is written to. This is
> then implemented in the ACLINT so that it does not have to include
> time_helper.h and tinker with the CPU internals. This again will allow
> new sources to be implemented more easily. It also ease maintenance by
> keeping internal CPU mechanics contained into the RISC-V target code and
> avoid potential duplication.
>
> Note that I would have liked to put the time_src interface as a qdev
> link property on the CPU but given the current state of the various
> RISC-V machines, this is not easy to do. Most of the time the CPU gets
> realized before the ACLINT so it is too late to set the link property.
> This would require further refactoring.
>
> Tested using `make check' and by booting Linux v6.17.6 in the virt
> machine with 4 CPUs. I can see an initial `time' register write
> (probably initial reset or OpenSBI) that correctly notifies the CPUs.
>
> Thanks
>
> Luc
Hi,
Ping, patches missing review: 8 and 9.
Thanks
--
Luc
>
> Luc Michel (9):
> target/riscv: drop unused include directive in time_helper.c
> hw/intc/riscv_aclint: fix coding style
> hw/intc/riscv_aclint: rename cpu_riscv_read_rtc to
> riscv_aclint_mtimer_get_ticks
> target/riscv: add the RISCVCPUTimeSrcIf interface
> hw/intc/riscv_aclint: implement the RISCVCPUTimeSrcIf interface
> target/riscv: replace env->rdtime_fn with a time source
> hw/intc/riscv_aclint: riscv_aclint_mtimer_get_ticks: get rid of void*
> argument
> target/riscv: RISCVCPUTimeSrcIf: add register_time_change_notifier
> hw/intc/riscv_aclint: implement the register_time_change_notifier
> method
>
> include/hw/intc/riscv_aclint.h | 1 +
> target/riscv/cpu-qom.h | 41 ++++++++++++++++++
> target/riscv/cpu.h | 9 ++--
> target/riscv/time_helper.h | 27 ++++++++++++
> hw/intc/riscv_aclint.c | 76 ++++++++++++++++++++++++----------
> target/riscv/cpu_helper.c | 7 ----
> target/riscv/csr.c | 24 +++++------
> target/riscv/time_helper.c | 42 +++++++++++++++----
> 8 files changed, 173 insertions(+), 54 deletions(-)
>
> --
> 2.51.0
>
--
^ permalink raw reply [flat|nested] 21+ messages in thread* Re: [PATCH 0/9] RISC-V CPU time source interface
2025-11-14 9:25 ` [PATCH 0/9] RISC-V CPU time source interface Luc Michel
@ 2025-11-20 17:16 ` Philippe Mathieu-Daudé
0 siblings, 0 replies; 21+ messages in thread
From: Philippe Mathieu-Daudé @ 2025-11-20 17:16 UTC (permalink / raw)
To: Luc Michel, qemu-devel, qemu-riscv
Cc: Palmer Dabbelt, Alistair Francis, Weiwei Li,
Daniel Henrique Barboza, Liu Zhiwei, Francisco Iglesias
On 14/11/25 10:25, Luc Michel wrote:
> Hi,
>
> Ping, patches missing review: 8 and 9.
Doh sorry, I don't remember why I stopped... I suppose I got interrupted
and forgot. Too bad this missed the soft-freeze, now we'll have to wait
after Xmas :/
^ permalink raw reply [flat|nested] 21+ messages in thread