The current 'timecmp' field in vmstate_riscv_mtimer is insufficient to keep
timers functional after migration.
If an mtimer's entry in 'mtimer->timers' is active at the time the snapshot
is taken, it means riscv_aclint_mtimer_write_timecmp() has written to
'mtimecmp' and scheduled a timer into QEMU's main loop 'timer_list'.
During snapshot save, these active timers must also be migrated; otherwise,
after snapshot load there is no mechanism to restore 'mtimer->timers' back
into the 'timer_list', and any pending timer events would be lost.
QEMU's migration framework commonly uses VMSTATE_TIMER_xxx macros to save
and restore 'QEMUTimer' variables. However, 'timers' is a pointer array
with variable length, and vmstate.h did not previously provide a helper
macro for such type.
This commit adds a new macro, 'VMSTATE_TIMER_PTR_VARRAY', to handle saving
and restoring a variable-length array of 'QEMUTimer *'. We then use this
macro to migrate the 'mtimer->timers' array, ensuring that timer events
remain scheduled correctly after snapshot load.
Reviewed-by: LIU Zhiwei <zhiwei_liu@linux.alibaba.com>
Signed-off-by: TANG Tiancheng <lyndra@linux.alibaba.com>
---
hw/intc/riscv_aclint.c | 6 ++++--
include/hw/intc/riscv_aclint.h | 4 ++++
2 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/hw/intc/riscv_aclint.c b/hw/intc/riscv_aclint.c
index 318a9c8248432a8cd4c3f3fa990739917ecf7ca1..9f4c36e965e2aa379d75c0a9f656177f0dd82a45 100644
--- a/hw/intc/riscv_aclint.c
+++ b/hw/intc/riscv_aclint.c
@@ -323,13 +323,15 @@ static void riscv_aclint_mtimer_reset_enter(Object *obj, ResetType type)
static const VMStateDescription vmstate_riscv_mtimer = {
.name = "riscv_mtimer",
- .version_id = 2,
- .minimum_version_id = 2,
+ .version_id = 3,
+ .minimum_version_id = 3,
.fields = (const VMStateField[]) {
VMSTATE_UINT64(time_delta, RISCVAclintMTimerState),
VMSTATE_VARRAY_UINT32(timecmp, RISCVAclintMTimerState,
num_harts, 0,
vmstate_info_uint64, uint64_t),
+ VMSTATE_TIMER_PTR_VARRAY(timers, RISCVAclintMTimerState,
+ num_harts),
VMSTATE_END_OF_LIST()
}
};
diff --git a/include/hw/intc/riscv_aclint.h b/include/hw/intc/riscv_aclint.h
index 693415eb6defe4454e5731a681e025f3bac3ad2e..4b7406eec005a06b7c040d8483a8790866a39297 100644
--- a/include/hw/intc/riscv_aclint.h
+++ b/include/hw/intc/riscv_aclint.h
@@ -80,4 +80,8 @@ enum {
RISCV_ACLINT_SWI_SIZE = 0x4000
};
+#define VMSTATE_TIMER_PTR_VARRAY(_f, _s, _f_n) \
+VMSTATE_VARRAY_OF_POINTER_UINT32(_f, _s, _f_n, 0, vmstate_info_timer, \
+ QEMUTimer *)
+
#endif
--
2.43.0
On Thu, Sep 11, 2025 at 7:58 PM TANG Tiancheng <lyndra@linux.alibaba.com> wrote: > > The current 'timecmp' field in vmstate_riscv_mtimer is insufficient to keep > timers functional after migration. > > If an mtimer's entry in 'mtimer->timers' is active at the time the snapshot > is taken, it means riscv_aclint_mtimer_write_timecmp() has written to > 'mtimecmp' and scheduled a timer into QEMU's main loop 'timer_list'. > > During snapshot save, these active timers must also be migrated; otherwise, > after snapshot load there is no mechanism to restore 'mtimer->timers' back > into the 'timer_list', and any pending timer events would be lost. > > QEMU's migration framework commonly uses VMSTATE_TIMER_xxx macros to save > and restore 'QEMUTimer' variables. However, 'timers' is a pointer array > with variable length, and vmstate.h did not previously provide a helper > macro for such type. > > This commit adds a new macro, 'VMSTATE_TIMER_PTR_VARRAY', to handle saving > and restoring a variable-length array of 'QEMUTimer *'. We then use this > macro to migrate the 'mtimer->timers' array, ensuring that timer events > remain scheduled correctly after snapshot load. > > Reviewed-by: LIU Zhiwei <zhiwei_liu@linux.alibaba.com> > Signed-off-by: TANG Tiancheng <lyndra@linux.alibaba.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Alistair > --- > hw/intc/riscv_aclint.c | 6 ++++-- > include/hw/intc/riscv_aclint.h | 4 ++++ > 2 files changed, 8 insertions(+), 2 deletions(-) > > diff --git a/hw/intc/riscv_aclint.c b/hw/intc/riscv_aclint.c > index 318a9c8248432a8cd4c3f3fa990739917ecf7ca1..9f4c36e965e2aa379d75c0a9f656177f0dd82a45 100644 > --- a/hw/intc/riscv_aclint.c > +++ b/hw/intc/riscv_aclint.c > @@ -323,13 +323,15 @@ static void riscv_aclint_mtimer_reset_enter(Object *obj, ResetType type) > > static const VMStateDescription vmstate_riscv_mtimer = { > .name = "riscv_mtimer", > - .version_id = 2, > - .minimum_version_id = 2, > + .version_id = 3, > + .minimum_version_id = 3, > .fields = (const VMStateField[]) { > VMSTATE_UINT64(time_delta, RISCVAclintMTimerState), > VMSTATE_VARRAY_UINT32(timecmp, RISCVAclintMTimerState, > num_harts, 0, > vmstate_info_uint64, uint64_t), > + VMSTATE_TIMER_PTR_VARRAY(timers, RISCVAclintMTimerState, > + num_harts), > VMSTATE_END_OF_LIST() > } > }; > diff --git a/include/hw/intc/riscv_aclint.h b/include/hw/intc/riscv_aclint.h > index 693415eb6defe4454e5731a681e025f3bac3ad2e..4b7406eec005a06b7c040d8483a8790866a39297 100644 > --- a/include/hw/intc/riscv_aclint.h > +++ b/include/hw/intc/riscv_aclint.h > @@ -80,4 +80,8 @@ enum { > RISCV_ACLINT_SWI_SIZE = 0x4000 > }; > > +#define VMSTATE_TIMER_PTR_VARRAY(_f, _s, _f_n) \ > +VMSTATE_VARRAY_OF_POINTER_UINT32(_f, _s, _f_n, 0, vmstate_info_timer, \ > + QEMUTimer *) > + > #endif > > -- > 2.43.0 > >
© 2016 - 2025 Red Hat, Inc.