* [PATCH v3 1/4] hw/intc: Save time_delta in RISC-V mtimer VMState
2025-09-11 9:56 [PATCH v3 0/4] Fix RISC-V timer migration issues TANG Tiancheng
@ 2025-09-11 9:56 ` TANG Tiancheng
2025-09-15 4:15 ` Alistair Francis
2025-09-11 9:56 ` [PATCH v3 2/4] migration: Add support for a variable-length array of UINT32 pointers TANG Tiancheng
` (4 subsequent siblings)
5 siblings, 1 reply; 12+ messages in thread
From: TANG Tiancheng @ 2025-09-11 9:56 UTC (permalink / raw)
To: qemu-devel
Cc: Palmer Dabbelt, Alistair Francis, Weiwei Li,
Daniel Henrique Barboza, Liu Zhiwei, qemu-riscv, Peter Xu,
Fabiano Rosas, TANG Tiancheng
In QEMU's RISC-V ACLINT timer model, 'mtime' is not stored directly as a
state variable. It is computed on demand as:
mtime = rtc_r + time_delta
where:
- 'rtc_r' is the current VM virtual time (in ticks) obtained via
cpu_riscv_read_rtc_raw() from QEMU_CLOCK_VIRTUAL.
- 'time_delta' is an offset applied when the guest writes a new 'mtime'
value via riscv_aclint_mtimer_write():
time_delta = value - rtc_r
Under this design, 'rtc_r' is assumed to be monotonically increasing
during VM execution. Even if the guest writes an 'mtime' value smaller
than the current one (making 'time_delta' negative in signed arithmetic,
or underflow in unsigned arithmetic), the computed 'mtime' remains
correct because 'rtc_r_new > rtc_r_old':
mtime_new = rtc_r_new + (value - rtc_r_old)
However, this monotonicity assumption breaks on snapshot load.
Before restoring a snapshot, QEMU resets the guest, which calls
riscv_aclint_mtimer_reset_enter() to set 'mtime' to 0 and recompute
'time_delta' as:
time_delta = 0 - rtc_r_reset
Here, the time_delta differs from the value that was present when the
snapshot was saved. As a result, subsequent reads produce a fixed offset
from the true mtime.
This can be observed with the 'date' command inside the guest: after loading
a snapshot, the reported time appears "frozen" at the save point, and only
resumes correctly after the guest has run long enough to compensate for the
erroneous offset.
The fix is to treat 'time_delta' as part of the device's migratable
state and save/restore it via vmstate. This preserves the correct
relation between 'rtc_r' and 'mtime' across snapshot save/load, ensuring
'mtime' continues incrementing from the precise saved value after
restore.
Reviewed-by: LIU Zhiwei <zhiwei_liu@linux.alibaba.com>
Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
Signed-off-by: TANG Tiancheng <lyndra@linux.alibaba.com>
---
hw/intc/riscv_aclint.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/hw/intc/riscv_aclint.c b/hw/intc/riscv_aclint.c
index 4623cfa029365c6cbdead4bd4a9f0d8b9e88b939..318a9c8248432a8cd4c3f3fa990739917ecf7ca1 100644
--- a/hw/intc/riscv_aclint.c
+++ b/hw/intc/riscv_aclint.c
@@ -323,9 +323,10 @@ static void riscv_aclint_mtimer_reset_enter(Object *obj, ResetType type)
static const VMStateDescription vmstate_riscv_mtimer = {
.name = "riscv_mtimer",
- .version_id = 1,
- .minimum_version_id = 1,
+ .version_id = 2,
+ .minimum_version_id = 2,
.fields = (const VMStateField[]) {
+ VMSTATE_UINT64(time_delta, RISCVAclintMTimerState),
VMSTATE_VARRAY_UINT32(timecmp, RISCVAclintMTimerState,
num_harts, 0,
vmstate_info_uint64, uint64_t),
--
2.43.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH v3 1/4] hw/intc: Save time_delta in RISC-V mtimer VMState
2025-09-11 9:56 ` [PATCH v3 1/4] hw/intc: Save time_delta in RISC-V mtimer VMState TANG Tiancheng
@ 2025-09-15 4:15 ` Alistair Francis
0 siblings, 0 replies; 12+ messages in thread
From: Alistair Francis @ 2025-09-15 4:15 UTC (permalink / raw)
To: TANG Tiancheng
Cc: qemu-devel, Palmer Dabbelt, Alistair Francis, Weiwei Li,
Daniel Henrique Barboza, Liu Zhiwei, qemu-riscv, Peter Xu,
Fabiano Rosas
On Thu, Sep 11, 2025 at 7:58 PM TANG Tiancheng <lyndra@linux.alibaba.com> wrote:
>
> In QEMU's RISC-V ACLINT timer model, 'mtime' is not stored directly as a
> state variable. It is computed on demand as:
>
> mtime = rtc_r + time_delta
>
> where:
> - 'rtc_r' is the current VM virtual time (in ticks) obtained via
> cpu_riscv_read_rtc_raw() from QEMU_CLOCK_VIRTUAL.
> - 'time_delta' is an offset applied when the guest writes a new 'mtime'
> value via riscv_aclint_mtimer_write():
>
> time_delta = value - rtc_r
>
> Under this design, 'rtc_r' is assumed to be monotonically increasing
> during VM execution. Even if the guest writes an 'mtime' value smaller
> than the current one (making 'time_delta' negative in signed arithmetic,
> or underflow in unsigned arithmetic), the computed 'mtime' remains
> correct because 'rtc_r_new > rtc_r_old':
>
> mtime_new = rtc_r_new + (value - rtc_r_old)
>
> However, this monotonicity assumption breaks on snapshot load.
>
> Before restoring a snapshot, QEMU resets the guest, which calls
> riscv_aclint_mtimer_reset_enter() to set 'mtime' to 0 and recompute
> 'time_delta' as:
>
> time_delta = 0 - rtc_r_reset
>
> Here, the time_delta differs from the value that was present when the
> snapshot was saved. As a result, subsequent reads produce a fixed offset
> from the true mtime.
>
> This can be observed with the 'date' command inside the guest: after loading
> a snapshot, the reported time appears "frozen" at the save point, and only
> resumes correctly after the guest has run long enough to compensate for the
> erroneous offset.
>
> The fix is to treat 'time_delta' as part of the device's migratable
> state and save/restore it via vmstate. This preserves the correct
> relation between 'rtc_r' and 'mtime' across snapshot save/load, ensuring
> 'mtime' continues incrementing from the precise saved value after
> restore.
>
> Reviewed-by: LIU Zhiwei <zhiwei_liu@linux.alibaba.com>
> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
> Signed-off-by: TANG Tiancheng <lyndra@linux.alibaba.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Alistair
> ---
> hw/intc/riscv_aclint.c | 5 +++--
> 1 file changed, 3 insertions(+), 2 deletions(-)
>
> diff --git a/hw/intc/riscv_aclint.c b/hw/intc/riscv_aclint.c
> index 4623cfa029365c6cbdead4bd4a9f0d8b9e88b939..318a9c8248432a8cd4c3f3fa990739917ecf7ca1 100644
> --- a/hw/intc/riscv_aclint.c
> +++ b/hw/intc/riscv_aclint.c
> @@ -323,9 +323,10 @@ static void riscv_aclint_mtimer_reset_enter(Object *obj, ResetType type)
>
> static const VMStateDescription vmstate_riscv_mtimer = {
> .name = "riscv_mtimer",
> - .version_id = 1,
> - .minimum_version_id = 1,
> + .version_id = 2,
> + .minimum_version_id = 2,
> .fields = (const VMStateField[]) {
> + VMSTATE_UINT64(time_delta, RISCVAclintMTimerState),
> VMSTATE_VARRAY_UINT32(timecmp, RISCVAclintMTimerState,
> num_harts, 0,
> vmstate_info_uint64, uint64_t),
>
> --
> 2.43.0
>
>
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH v3 2/4] migration: Add support for a variable-length array of UINT32 pointers
2025-09-11 9:56 [PATCH v3 0/4] Fix RISC-V timer migration issues TANG Tiancheng
2025-09-11 9:56 ` [PATCH v3 1/4] hw/intc: Save time_delta in RISC-V mtimer VMState TANG Tiancheng
@ 2025-09-11 9:56 ` TANG Tiancheng
2025-09-15 4:16 ` Alistair Francis
2025-09-11 9:56 ` [PATCH v3 3/4] hw/intc: Save timers array in RISC-V mtimer VMState TANG Tiancheng
` (3 subsequent siblings)
5 siblings, 1 reply; 12+ messages in thread
From: TANG Tiancheng @ 2025-09-11 9:56 UTC (permalink / raw)
To: qemu-devel
Cc: Palmer Dabbelt, Alistair Francis, Weiwei Li,
Daniel Henrique Barboza, Liu Zhiwei, qemu-riscv, Peter Xu,
Fabiano Rosas, TANG Tiancheng
Add support for defining a vmstate field which is a variable-length array
of pointers, and use this to define a VMSTATE_TIMER_PTR_VARRAY() which allows
a variable-length array of QEMUTimer* to be used by devices.
Message-id: 20250909-timers-v1-0-7ee18a9d8f4b@linux.alibaba.com
Reviewed-by: LIU Zhiwei <zhiwei_liu@linux.alibaba.com>
Reviewed-by: Peter Xu <peterx@redhat.com>
Signed-off-by: TANG Tiancheng <lyndra@linux.alibaba.com>
---
include/migration/vmstate.h | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
index 1ff7bd9ac425ba67cd5ca7ad97bcf570f9e19abe..1cfddf31b54090f0f63380794092858b4bed8bcf 100644
--- a/include/migration/vmstate.h
+++ b/include/migration/vmstate.h
@@ -522,6 +522,16 @@ extern const VMStateInfo vmstate_info_qlist;
.offset = vmstate_offset_array(_s, _f, _type*, _n), \
}
+#define VMSTATE_VARRAY_OF_POINTER_UINT32(_field, _state, _field_num, _version, _info, _type) { \
+ .name = (stringify(_field)), \
+ .version_id = (_version), \
+ .num_offset = vmstate_offset_value(_state, _field_num, uint32_t), \
+ .info = &(_info), \
+ .size = sizeof(_type), \
+ .flags = VMS_VARRAY_UINT32 | VMS_ARRAY_OF_POINTER | VMS_POINTER, \
+ .offset = vmstate_offset_pointer(_state, _field, _type), \
+}
+
#define VMSTATE_STRUCT_SUB_ARRAY(_field, _state, _start, _num, _version, _vmsd, _type) { \
.name = (stringify(_field)), \
.version_id = (_version), \
--
2.43.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH v3 2/4] migration: Add support for a variable-length array of UINT32 pointers
2025-09-11 9:56 ` [PATCH v3 2/4] migration: Add support for a variable-length array of UINT32 pointers TANG Tiancheng
@ 2025-09-15 4:16 ` Alistair Francis
0 siblings, 0 replies; 12+ messages in thread
From: Alistair Francis @ 2025-09-15 4:16 UTC (permalink / raw)
To: TANG Tiancheng
Cc: qemu-devel, Palmer Dabbelt, Alistair Francis, Weiwei Li,
Daniel Henrique Barboza, Liu Zhiwei, qemu-riscv, Peter Xu,
Fabiano Rosas
On Thu, Sep 11, 2025 at 7:58 PM TANG Tiancheng <lyndra@linux.alibaba.com> wrote:
>
> Add support for defining a vmstate field which is a variable-length array
> of pointers, and use this to define a VMSTATE_TIMER_PTR_VARRAY() which allows
> a variable-length array of QEMUTimer* to be used by devices.
>
> Message-id: 20250909-timers-v1-0-7ee18a9d8f4b@linux.alibaba.com
> Reviewed-by: LIU Zhiwei <zhiwei_liu@linux.alibaba.com>
> Reviewed-by: Peter Xu <peterx@redhat.com>
> Signed-off-by: TANG Tiancheng <lyndra@linux.alibaba.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Alistair
> ---
> include/migration/vmstate.h | 10 ++++++++++
> 1 file changed, 10 insertions(+)
>
> diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
> index 1ff7bd9ac425ba67cd5ca7ad97bcf570f9e19abe..1cfddf31b54090f0f63380794092858b4bed8bcf 100644
> --- a/include/migration/vmstate.h
> +++ b/include/migration/vmstate.h
> @@ -522,6 +522,16 @@ extern const VMStateInfo vmstate_info_qlist;
> .offset = vmstate_offset_array(_s, _f, _type*, _n), \
> }
>
> +#define VMSTATE_VARRAY_OF_POINTER_UINT32(_field, _state, _field_num, _version, _info, _type) { \
> + .name = (stringify(_field)), \
> + .version_id = (_version), \
> + .num_offset = vmstate_offset_value(_state, _field_num, uint32_t), \
> + .info = &(_info), \
> + .size = sizeof(_type), \
> + .flags = VMS_VARRAY_UINT32 | VMS_ARRAY_OF_POINTER | VMS_POINTER, \
> + .offset = vmstate_offset_pointer(_state, _field, _type), \
> +}
> +
> #define VMSTATE_STRUCT_SUB_ARRAY(_field, _state, _start, _num, _version, _vmsd, _type) { \
> .name = (stringify(_field)), \
> .version_id = (_version), \
>
> --
> 2.43.0
>
>
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH v3 3/4] hw/intc: Save timers array in RISC-V mtimer VMState
2025-09-11 9:56 [PATCH v3 0/4] Fix RISC-V timer migration issues TANG Tiancheng
2025-09-11 9:56 ` [PATCH v3 1/4] hw/intc: Save time_delta in RISC-V mtimer VMState TANG Tiancheng
2025-09-11 9:56 ` [PATCH v3 2/4] migration: Add support for a variable-length array of UINT32 pointers TANG Tiancheng
@ 2025-09-11 9:56 ` TANG Tiancheng
2025-09-15 4:20 ` Alistair Francis
2025-09-11 9:56 ` [PATCH v3 4/4] target/riscv: Save stimer and vstimer in CPU vmstate TANG Tiancheng
` (2 subsequent siblings)
5 siblings, 1 reply; 12+ messages in thread
From: TANG Tiancheng @ 2025-09-11 9:56 UTC (permalink / raw)
To: qemu-devel
Cc: Palmer Dabbelt, Alistair Francis, Weiwei Li,
Daniel Henrique Barboza, Liu Zhiwei, qemu-riscv, Peter Xu,
Fabiano Rosas, TANG Tiancheng
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
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH v3 3/4] hw/intc: Save timers array in RISC-V mtimer VMState
2025-09-11 9:56 ` [PATCH v3 3/4] hw/intc: Save timers array in RISC-V mtimer VMState TANG Tiancheng
@ 2025-09-15 4:20 ` Alistair Francis
0 siblings, 0 replies; 12+ messages in thread
From: Alistair Francis @ 2025-09-15 4:20 UTC (permalink / raw)
To: TANG Tiancheng
Cc: qemu-devel, Palmer Dabbelt, Alistair Francis, Weiwei Li,
Daniel Henrique Barboza, Liu Zhiwei, qemu-riscv, Peter Xu,
Fabiano Rosas
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
>
>
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH v3 4/4] target/riscv: Save stimer and vstimer in CPU vmstate
2025-09-11 9:56 [PATCH v3 0/4] Fix RISC-V timer migration issues TANG Tiancheng
` (2 preceding siblings ...)
2025-09-11 9:56 ` [PATCH v3 3/4] hw/intc: Save timers array in RISC-V mtimer VMState TANG Tiancheng
@ 2025-09-11 9:56 ` TANG Tiancheng
2025-09-15 4:21 ` Alistair Francis
2025-09-15 4:25 ` [PATCH v3 0/4] Fix RISC-V timer migration issues Alistair Francis
2025-10-04 7:16 ` Michael Tokarev
5 siblings, 1 reply; 12+ messages in thread
From: TANG Tiancheng @ 2025-09-11 9:56 UTC (permalink / raw)
To: qemu-devel
Cc: Palmer Dabbelt, Alistair Francis, Weiwei Li,
Daniel Henrique Barboza, Liu Zhiwei, qemu-riscv, Peter Xu,
Fabiano Rosas, TANG Tiancheng
vmstate_riscv_cpu was missing env.stimer and env.vstimer.
Without migrating these QEMUTimer fields, active S/VS-mode
timer events are lost after snapshot or migration.
Add VMSTATE_TIMER_PTR() entries to save and restore them.
Reviewed-by: LIU Zhiwei <zhiwei_liu@linux.alibaba.com>
Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
Signed-off-by: TANG Tiancheng <lyndra@linux.alibaba.com>
---
target/riscv/machine.c | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/target/riscv/machine.c b/target/riscv/machine.c
index 1600ec44f0b755fdd49fc0df47c2288c9940afe0..51e0567ed30cbab5e791ea904165bc1854709192 100644
--- a/target/riscv/machine.c
+++ b/target/riscv/machine.c
@@ -400,6 +400,30 @@ static const VMStateDescription vmstate_ssp = {
}
};
+static bool sstc_timer_needed(void *opaque)
+{
+ RISCVCPU *cpu = opaque;
+ CPURISCVState *env = &cpu->env;
+
+ if (!cpu->cfg.ext_sstc) {
+ return false;
+ }
+
+ return env->stimer != NULL || env->vstimer != NULL;
+}
+
+static const VMStateDescription vmstate_sstc = {
+ .name = "cpu/timer",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = sstc_timer_needed,
+ .fields = (const VMStateField[]) {
+ VMSTATE_TIMER_PTR(env.stimer, RISCVCPU),
+ VMSTATE_TIMER_PTR(env.vstimer, RISCVCPU),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
const VMStateDescription vmstate_riscv_cpu = {
.name = "cpu",
.version_id = 10,
@@ -476,6 +500,7 @@ const VMStateDescription vmstate_riscv_cpu = {
&vmstate_elp,
&vmstate_ssp,
&vmstate_ctr,
+ &vmstate_sstc,
NULL
}
};
--
2.43.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH v3 4/4] target/riscv: Save stimer and vstimer in CPU vmstate
2025-09-11 9:56 ` [PATCH v3 4/4] target/riscv: Save stimer and vstimer in CPU vmstate TANG Tiancheng
@ 2025-09-15 4:21 ` Alistair Francis
0 siblings, 0 replies; 12+ messages in thread
From: Alistair Francis @ 2025-09-15 4:21 UTC (permalink / raw)
To: TANG Tiancheng
Cc: qemu-devel, Palmer Dabbelt, Alistair Francis, Weiwei Li,
Daniel Henrique Barboza, Liu Zhiwei, qemu-riscv, Peter Xu,
Fabiano Rosas
On Thu, Sep 11, 2025 at 7:59 PM TANG Tiancheng <lyndra@linux.alibaba.com> wrote:
>
> vmstate_riscv_cpu was missing env.stimer and env.vstimer.
> Without migrating these QEMUTimer fields, active S/VS-mode
> timer events are lost after snapshot or migration.
>
> Add VMSTATE_TIMER_PTR() entries to save and restore them.
>
> Reviewed-by: LIU Zhiwei <zhiwei_liu@linux.alibaba.com>
> Reviewed-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
> Signed-off-by: TANG Tiancheng <lyndra@linux.alibaba.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Alistair
> ---
> target/riscv/machine.c | 25 +++++++++++++++++++++++++
> 1 file changed, 25 insertions(+)
>
> diff --git a/target/riscv/machine.c b/target/riscv/machine.c
> index 1600ec44f0b755fdd49fc0df47c2288c9940afe0..51e0567ed30cbab5e791ea904165bc1854709192 100644
> --- a/target/riscv/machine.c
> +++ b/target/riscv/machine.c
> @@ -400,6 +400,30 @@ static const VMStateDescription vmstate_ssp = {
> }
> };
>
> +static bool sstc_timer_needed(void *opaque)
> +{
> + RISCVCPU *cpu = opaque;
> + CPURISCVState *env = &cpu->env;
> +
> + if (!cpu->cfg.ext_sstc) {
> + return false;
> + }
> +
> + return env->stimer != NULL || env->vstimer != NULL;
> +}
> +
> +static const VMStateDescription vmstate_sstc = {
> + .name = "cpu/timer",
> + .version_id = 1,
> + .minimum_version_id = 1,
> + .needed = sstc_timer_needed,
> + .fields = (const VMStateField[]) {
> + VMSTATE_TIMER_PTR(env.stimer, RISCVCPU),
> + VMSTATE_TIMER_PTR(env.vstimer, RISCVCPU),
> + VMSTATE_END_OF_LIST()
> + }
> +};
> +
> const VMStateDescription vmstate_riscv_cpu = {
> .name = "cpu",
> .version_id = 10,
> @@ -476,6 +500,7 @@ const VMStateDescription vmstate_riscv_cpu = {
> &vmstate_elp,
> &vmstate_ssp,
> &vmstate_ctr,
> + &vmstate_sstc,
> NULL
> }
> };
>
> --
> 2.43.0
>
>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v3 0/4] Fix RISC-V timer migration issues
2025-09-11 9:56 [PATCH v3 0/4] Fix RISC-V timer migration issues TANG Tiancheng
` (3 preceding siblings ...)
2025-09-11 9:56 ` [PATCH v3 4/4] target/riscv: Save stimer and vstimer in CPU vmstate TANG Tiancheng
@ 2025-09-15 4:25 ` Alistair Francis
2025-10-04 7:16 ` Michael Tokarev
5 siblings, 0 replies; 12+ messages in thread
From: Alistair Francis @ 2025-09-15 4:25 UTC (permalink / raw)
To: TANG Tiancheng
Cc: qemu-devel, Palmer Dabbelt, Alistair Francis, Weiwei Li,
Daniel Henrique Barboza, Liu Zhiwei, qemu-riscv, Peter Xu,
Fabiano Rosas
On Thu, Sep 11, 2025 at 7:59 PM TANG Tiancheng <lyndra@linux.alibaba.com> wrote:
>
> This patch set fixes several timer-related migration issues in QEMU's
> RISC-V implementation that cause timer events to be lost or behave
> incorrectly after snapshot save/restore or live migration.
>
> The problems addressed are:
>
> 1. ACLINT mtimer time_delta not migrated: The time_delta field in
> RISCVAclintMTimerState was missing from vmstate, causing incorrect
> mtime values after snapshot restore. This resulted in guest time
> appearing "frozen" until enough virtual time elapsed to compensate
> for the offset error.
>
> 2. ACLINT mtimer timers array not migrated: Active timer events
> scheduled via riscv_aclint_mtimer_write_timecmp() were not being
> migrated, causing pending timer interrupts to be lost after restore.
>
> 3. CPU stimer/vstimer not migrated: The S-mode and VS-mode timer
> pointers in CPURISCVState were missing from vmstate_riscv_cpu,
> causing supervisor-level timer events to be lost.
>
> The patch set introduces a new VMSTATE_TIMER_PTR_VARRAY macro to handle
> migration of variable-length timer pointer arrays, and adds the missing
> timer fields to the appropriate vmstate structures.
>
> Signed-off-by: TANG Tiancheng <lyndra@linux.alibaba.com>
Thanks!
Applied to riscv-to-apply.next
Alistair
> ---
> Changes in v3:
> - Remove 'include/' of the subject at patch v2 2/4.
> - Added Reviewed-by from Peter Xu.
> - Link to v2: https://lore.kernel.org/qemu-devel/20250910-timers-v2-0-31359f1f6ee8@linux.alibaba.com
>
> Changes in v2:
> - Split VMSTATE_VARRAY_OF_POINTER_UINT32() into a separate patch,
> and define VMSTATE_TIMER_PTR_VARRAY() in riscv_aclint.h.
> - Added Reviewed-by from Daniel Henrique Barboza.
> - Link to v1: https://lore.kernel.org/qemu-devel/20250909-timers-v1-0-7ee18a9d8f4b@linux.alibaba.com
>
> ---
> TANG Tiancheng (4):
> hw/intc: Save time_delta in RISC-V mtimer VMState
> migration: Add support for a variable-length array of UINT32 pointers
> hw/intc: Save timers array in RISC-V mtimer VMState
> target/riscv: Save stimer and vstimer in CPU vmstate
>
> hw/intc/riscv_aclint.c | 7 +++++--
> include/hw/intc/riscv_aclint.h | 4 ++++
> include/migration/vmstate.h | 10 ++++++++++
> target/riscv/machine.c | 25 +++++++++++++++++++++++++
> 4 files changed, 44 insertions(+), 2 deletions(-)
> ---
> base-commit: 6a9fa5ef3230a7d51e0d953a59ee9ef10af705b8
> change-id: 20250909-timers-18c2c67b1a2a
>
> Best regards,
> --
> TANG Tiancheng <lyndra@linux.alibaba.com>
>
>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v3 0/4] Fix RISC-V timer migration issues
2025-09-11 9:56 [PATCH v3 0/4] Fix RISC-V timer migration issues TANG Tiancheng
` (4 preceding siblings ...)
2025-09-15 4:25 ` [PATCH v3 0/4] Fix RISC-V timer migration issues Alistair Francis
@ 2025-10-04 7:16 ` Michael Tokarev
2025-10-09 2:35 ` Alistair Francis
5 siblings, 1 reply; 12+ messages in thread
From: Michael Tokarev @ 2025-10-04 7:16 UTC (permalink / raw)
To: TANG Tiancheng, qemu-devel
Cc: Palmer Dabbelt, Alistair Francis, Weiwei Li,
Daniel Henrique Barboza, Liu Zhiwei, qemu-riscv, Peter Xu,
Fabiano Rosas, qemu-stable
On 9/11/25 12:56, TANG Tiancheng wrote:
> This patch set fixes several timer-related migration issues in QEMU's
> RISC-V implementation that cause timer events to be lost or behave
> incorrectly after snapshot save/restore or live migration.
>
> The problems addressed are:
>
> 1. ACLINT mtimer time_delta not migrated: The time_delta field in
> RISCVAclintMTimerState was missing from vmstate, causing incorrect
> mtime values after snapshot restore. This resulted in guest time
> appearing "frozen" until enough virtual time elapsed to compensate
> for the offset error.
>
> 2. ACLINT mtimer timers array not migrated: Active timer events
> scheduled via riscv_aclint_mtimer_write_timecmp() were not being
> migrated, causing pending timer interrupts to be lost after restore.
>
> 3. CPU stimer/vstimer not migrated: The S-mode and VS-mode timer
> pointers in CPURISCVState were missing from vmstate_riscv_cpu,
> causing supervisor-level timer events to be lost.
>
> The patch set introduces a new VMSTATE_TIMER_PTR_VARRAY macro to handle
> migration of variable-length timer pointer arrays, and adds the missing
> timer fields to the appropriate vmstate structures.
>
> Signed-off-by: TANG Tiancheng <lyndra@linux.alibaba.com>
> ---
> Changes in v3:
> - Remove 'include/' of the subject at patch v2 2/4.
> - Added Reviewed-by from Peter Xu.
> - Link to v2: https://lore.kernel.org/qemu-devel/20250910-timers-v2-0-31359f1f6ee8@linux.alibaba.com
>
> Changes in v2:
> - Split VMSTATE_VARRAY_OF_POINTER_UINT32() into a separate patch,
> and define VMSTATE_TIMER_PTR_VARRAY() in riscv_aclint.h.
> - Added Reviewed-by from Daniel Henrique Barboza.
> - Link to v1: https://lore.kernel.org/qemu-devel/20250909-timers-v1-0-7ee18a9d8f4b@linux.alibaba.com
>
> ---
> TANG Tiancheng (4):
> hw/intc: Save time_delta in RISC-V mtimer VMState
> migration: Add support for a variable-length array of UINT32 pointers
> hw/intc: Save timers array in RISC-V mtimer VMState
> target/riscv: Save stimer and vstimer in CPU vmstate
Am I right this stuff is not back-portable to previous qemu
stable releases, as it introduces new fields into the migration
stream which, which can't be picked up by these releases?
From the description it seems like all this stuff should be fixed
in previous stable qemu releases too.
Thanks,
/mjt
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v3 0/4] Fix RISC-V timer migration issues
2025-10-04 7:16 ` Michael Tokarev
@ 2025-10-09 2:35 ` Alistair Francis
0 siblings, 0 replies; 12+ messages in thread
From: Alistair Francis @ 2025-10-09 2:35 UTC (permalink / raw)
To: Michael Tokarev
Cc: TANG Tiancheng, qemu-devel, Palmer Dabbelt, Alistair Francis,
Weiwei Li, Daniel Henrique Barboza, Liu Zhiwei, qemu-riscv,
Peter Xu, Fabiano Rosas, qemu-stable
On Sat, Oct 4, 2025 at 5:19 PM Michael Tokarev <mjt@tls.msk.ru> wrote:
>
> On 9/11/25 12:56, TANG Tiancheng wrote:
> > This patch set fixes several timer-related migration issues in QEMU's
> > RISC-V implementation that cause timer events to be lost or behave
> > incorrectly after snapshot save/restore or live migration.
> >
> > The problems addressed are:
> >
> > 1. ACLINT mtimer time_delta not migrated: The time_delta field in
> > RISCVAclintMTimerState was missing from vmstate, causing incorrect
> > mtime values after snapshot restore. This resulted in guest time
> > appearing "frozen" until enough virtual time elapsed to compensate
> > for the offset error.
> >
> > 2. ACLINT mtimer timers array not migrated: Active timer events
> > scheduled via riscv_aclint_mtimer_write_timecmp() were not being
> > migrated, causing pending timer interrupts to be lost after restore.
> >
> > 3. CPU stimer/vstimer not migrated: The S-mode and VS-mode timer
> > pointers in CPURISCVState were missing from vmstate_riscv_cpu,
> > causing supervisor-level timer events to be lost.
> >
> > The patch set introduces a new VMSTATE_TIMER_PTR_VARRAY macro to handle
> > migration of variable-length timer pointer arrays, and adds the missing
> > timer fields to the appropriate vmstate structures.
> >
> > Signed-off-by: TANG Tiancheng <lyndra@linux.alibaba.com>
> > ---
> > Changes in v3:
> > - Remove 'include/' of the subject at patch v2 2/4.
> > - Added Reviewed-by from Peter Xu.
> > - Link to v2: https://lore.kernel.org/qemu-devel/20250910-timers-v2-0-31359f1f6ee8@linux.alibaba.com
> >
> > Changes in v2:
> > - Split VMSTATE_VARRAY_OF_POINTER_UINT32() into a separate patch,
> > and define VMSTATE_TIMER_PTR_VARRAY() in riscv_aclint.h.
> > - Added Reviewed-by from Daniel Henrique Barboza.
> > - Link to v1: https://lore.kernel.org/qemu-devel/20250909-timers-v1-0-7ee18a9d8f4b@linux.alibaba.com
> >
> > ---
> > TANG Tiancheng (4):
> > hw/intc: Save time_delta in RISC-V mtimer VMState
> > migration: Add support for a variable-length array of UINT32 pointers
> > hw/intc: Save timers array in RISC-V mtimer VMState
> > target/riscv: Save stimer and vstimer in CPU vmstate
>
> Am I right this stuff is not back-portable to previous qemu
> stable releases, as it introduces new fields into the migration
> stream which, which can't be picked up by these releases?
Yes, I don't think this should be backported as it'stargetting migration.
Alistair
>
> From the description it seems like all this stuff should be fixed
> in previous stable qemu releases too.
>
> Thanks,
>
> /mjt
>
^ permalink raw reply [flat|nested] 12+ messages in thread