* [PATCH] accel/mshv: freeze time during TSC MSR write
@ 2026-11-06 14:39 Magnus Kulke
2026-11-09 16:22 ` Doru Blânzeanu
0 siblings, 1 reply; 3+ messages in thread
From: Magnus Kulke @ 2026-11-06 14:39 UTC (permalink / raw)
To: qemu-devel
Cc: Michael S. Tsirkin, Paolo Bonzini, Doru Blânzeanu,
Magnus Kulke, Wei Liu, Wei Liu, Feng Liang, Richard Henderson,
Doru Blânzeanu
A regression was introduced when the HV_X64_REGISTER_TSC MSR state is
being written to the hypervisor as part of the migration framework. If
the MSR is written without the time being frozen, the tsc_page (a
hyper-v enlightenment) is zeroed out and cannot be used by a guest,
which results in a performance regression, because the guest falls back
to costly reads of HV_X64_MSR_TIME_REF_COUNT.
An implementation of pre_resume_vm hook was added to handle the clock
lifecycle, relying on the dirty_vcpu state to avoid redundant state
writes.
Fixes: d540dcc5e28c (target/i386/mshv: migrate MSRs)
Signed-off-by: Magnus Kulke <magnuskulke@linux.microsoft.com>
---
accel/mshv/mshv-all.c | 33 ++++++++++++-
hw/i386/mshv/clock.c | 111 +++++++++++++++++++++++++++++-------------
include/system/mshv.h | 4 +-
3 files changed, 113 insertions(+), 35 deletions(-)
diff --git a/accel/mshv/mshv-all.c b/accel/mshv/mshv-all.c
index d820a67b95..ae7577d407 100644
--- a/accel/mshv/mshv-all.c
+++ b/accel/mshv/mshv-all.c
@@ -34,6 +34,7 @@
#include "accel/accel-cpu-ops.h"
#include "exec/cpu-common.h"
#include "system/cpus.h"
+#include "system/hw_accel.h"
#include "system/runstate.h"
#include "system/accel-blocker.h"
#include "system/address-spaces.h"
@@ -578,7 +579,10 @@ static int mshv_init(AccelState *as, MachineState *ms)
register_savevm_live("mshv", 0, 1, &savevm_mshv, s);
- mshv_clock_init();
+ ret = mshv_clock_init(vm_fd);
+ if (ret < 0) {
+ return -1;
+ }
return 0;
}
@@ -927,6 +931,32 @@ static void mshv_cpu_synchronize_pre_loadvm(CPUState *cpu)
run_on_cpu(cpu, do_mshv_cpu_synchronize_pre_loadvm, RUN_ON_CPU_NULL);
}
+static void mshv_pre_resume_vm(AccelState *as, bool step_pending)
+{
+ MshvState *s = MSHV_STATE(as);
+ CPUState *cpu;
+ int ret, vm_fd = s->vm;
+
+ ret = mshv_clock_prepare_resume(vm_fd);
+ if (ret < 0) {
+ error_report("Failed to prepare clock for resume");
+ abort();
+ }
+
+ CPU_FOREACH(cpu) {
+ if (!cpu->vcpu_dirty) {
+ continue;
+ }
+ cpu_synchronize_post_init(cpu);
+ }
+
+ ret = mshv_clock_finish_resume(vm_fd);
+ if (ret < 0) {
+ error_report("Failed to finish clock for resume");
+ abort();
+ }
+}
+
static void do_mshv_cpu_synchronize(CPUState *cpu, run_on_cpu_data arg)
{
if (!cpu->vcpu_dirty) {
@@ -962,6 +992,7 @@ static void mshv_accel_class_init(ObjectClass *oc, const void *data)
ac->name = "MSHV";
ac->init_machine = mshv_init;
ac->allowed = &mshv_allowed;
+ ac->pre_resume_vm = mshv_pre_resume_vm;
}
static void mshv_accel_instance_init(Object *obj)
diff --git a/hw/i386/mshv/clock.c b/hw/i386/mshv/clock.c
index 02c586503a..2a03d3cef9 100644
--- a/hw/i386/mshv/clock.c
+++ b/hw/i386/mshv/clock.c
@@ -29,6 +29,7 @@
typedef struct MshvClockState {
uint64_t ref_time;
bool ref_time_pending;
+ bool time_frozen;
} MshvClockState;
static MshvClockState mshv_clock;
@@ -110,52 +111,85 @@ static int mshv_set_time_freeze(int vm_fd, int freeze)
return 0;
}
-static void mshv_clock_vm_state_change(void *opaque, bool running,
- RunState state)
-{
- MshvClockState *s = opaque;
- int vm_fd = mshv_state->vm;
+static int ensure_time_frozen(int vm_fd) {
int ret;
- if (running) {
- /* Skip if we have nothing to restore, e.g. on initial boot. */
- if (!s->ref_time_pending) {
- return;
- }
+ /* Ensure time is frozen */
+ if (mshv_clock.time_frozen) {
+ return 0;
+ }
- ret = mshv_set_time_freeze(vm_fd, 1);
- if (ret < 0) {
- error_report("Failed to freeze partition time on resume");
- abort();
- }
+ ret = mshv_set_time_freeze(vm_fd, 1);
+ if (ret < 0) {
+ error_report("Failed to freeze partition");
+ return -1;
+ }
+ mshv_clock.time_frozen = true;
+ return 0;
+}
+
+int mshv_clock_prepare_resume(int vm_fd) {
+ return ensure_time_frozen(vm_fd);
+}
+
+int mshv_clock_finish_resume(int vm_fd) {
+ int ret;
+ MshvClockState *s = &mshv_clock;
+
+ assert(mshv_clock.time_frozen);
+
+ /* Skip if we have nothing to restore, e.g. on initial boot. */
+ if (s->ref_time_pending) {
/* INVARIANT: reference time can only be written if time is frozen. */
ret = mshv_set_reference_time(vm_fd, s->ref_time);
if (ret < 0) {
error_report("Failed to restore reference time on resume");
- abort();
+ return -1;
}
+ s->ref_time_pending = false;
+ }
- if (mshv_set_time_freeze(vm_fd, 0) < 0) {
- error_report("Failed to unfreeze partition time on resume");
- abort();
- }
+ ret = mshv_set_time_freeze(vm_fd, 0);
+ if (ret < 0) {
+ error_report("Failed to thaw partition");
+ return -1;
+ }
+ mshv_clock.time_frozen = false;
- s->ref_time_pending = false;
- } else {
- /* Skip if we already have a to-be-set ref time */
- if (s->ref_time_pending) {
- return;
- }
+ return 0;
+}
- ret = mshv_get_reference_time(vm_fd, &s->ref_time);
- if (ret < 0) {
- error_report("Failed to capture reference time on stop");
- abort();
- }
+static void mshv_clock_vm_state_change(void *opaque, bool running,
+ RunState state)
+{
+ MshvClockState *s = opaque;
+ int vm_fd = mshv_state->vm;
+ int ret;
- s->ref_time_pending = true;
+ if (running) {
+ return;
}
+
+ /* Ensure the time if frozen before we capture the reference time. */
+ ret = ensure_time_frozen(vm_fd);
+ if (ret < 0) {
+ error_report("Failed to freeze partition time on stop");
+ abort();
+ }
+
+ /* Skip if we already have a to-be-set ref time */
+ if (s->ref_time_pending) {
+ return;
+ }
+
+ ret = mshv_get_reference_time(vm_fd, &s->ref_time);
+ if (ret < 0) {
+ error_report("Failed to capture reference time on stop");
+ abort();
+ }
+
+ s->ref_time_pending = true;
}
/*
@@ -182,8 +216,19 @@ static const VMStateDescription vmstate_mshv_clock = {
},
};
-void mshv_clock_init(void)
+int mshv_clock_init(int vm_fd)
{
+ int ret;
+
+ ret = mshv_set_time_freeze(vm_fd, 1);
+ if (ret < 0) {
+ error_report("Failed to freeze partition time on init");
+ return -1;
+ }
+ mshv_clock.time_frozen = true;
+
vmstate_register(NULL, 0, &vmstate_mshv_clock, &mshv_clock);
qemu_add_vm_change_state_handler(mshv_clock_vm_state_change, &mshv_clock);
+
+ return 0;
}
diff --git a/include/system/mshv.h b/include/system/mshv.h
index f98ddff9b5..864f2aa34d 100644
--- a/include/system/mshv.h
+++ b/include/system/mshv.h
@@ -58,7 +58,9 @@ DECLARE_INSTANCE_CHECKER(MshvState, MSHV_STATE,
extern MshvState *mshv_state;
/* clock (partition reference time) */
-void mshv_clock_init(void);
+int mshv_clock_init(int vm_fd);
+int mshv_clock_prepare_resume(int vm_fd);
+int mshv_clock_finish_resume(int vm_fd);
/* interrupt */
int mshv_request_interrupt(MshvState *mshv_state, uint32_t interrupt_type, uint32_t vector,
--
2.34.1
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH] accel/mshv: freeze time during TSC MSR write
2026-11-06 14:39 [PATCH] accel/mshv: freeze time during TSC MSR write Magnus Kulke
@ 2026-11-09 16:22 ` Doru Blânzeanu
2026-11-11 19:36 ` Magnus Kulke
0 siblings, 1 reply; 3+ messages in thread
From: Doru Blânzeanu @ 2026-11-09 16:22 UTC (permalink / raw)
To: Magnus Kulke
Cc: qemu-devel, Michael S. Tsirkin, Paolo Bonzini, Wei Liu, Wei Liu,
Feng Liang, Richard Henderson, Doru Blânzeanu
On Fri, Nov 06, 2026 at 03:39:28PM +0100, Magnus Kulke wrote:
> A regression was introduced when the HV_X64_REGISTER_TSC MSR state is
> being written to the hypervisor as part of the migration framework. If
> the MSR is written without the time being frozen, the tsc_page (a
> hyper-v enlightenment) is zeroed out and cannot be used by a guest,
> which results in a performance regression, because the guest falls back
> to costly reads of HV_X64_MSR_TIME_REF_COUNT.
>
> An implementation of pre_resume_vm hook was added to handle the clock
> lifecycle, relying on the dirty_vcpu state to avoid redundant state
> writes.
>
> Fixes: d540dcc5e28c (target/i386/mshv: migrate MSRs)
>
> Signed-off-by: Magnus Kulke <magnuskulke@linux.microsoft.com>
> ---
> accel/mshv/mshv-all.c | 33 ++++++++++++-
> hw/i386/mshv/clock.c | 111 +++++++++++++++++++++++++++++-------------
> include/system/mshv.h | 4 +-
> 3 files changed, 113 insertions(+), 35 deletions(-)
>
> diff --git a/accel/mshv/mshv-all.c b/accel/mshv/mshv-all.c
> index d820a67b95..ae7577d407 100644
> --- a/accel/mshv/mshv-all.c
> +++ b/accel/mshv/mshv-all.c
> @@ -34,6 +34,7 @@
> #include "accel/accel-cpu-ops.h"
> #include "exec/cpu-common.h"
> #include "system/cpus.h"
> +#include "system/hw_accel.h"
> #include "system/runstate.h"
> #include "system/accel-blocker.h"
> #include "system/address-spaces.h"
> @@ -578,7 +579,10 @@ static int mshv_init(AccelState *as, MachineState *ms)
>
> register_savevm_live("mshv", 0, 1, &savevm_mshv, s);
>
> - mshv_clock_init();
> + ret = mshv_clock_init(vm_fd);
> + if (ret < 0) {
> + return -1;
> + }
>
> return 0;
> }
> @@ -927,6 +931,32 @@ static void mshv_cpu_synchronize_pre_loadvm(CPUState *cpu)
> run_on_cpu(cpu, do_mshv_cpu_synchronize_pre_loadvm, RUN_ON_CPU_NULL);
> }
>
> +static void mshv_pre_resume_vm(AccelState *as, bool step_pending)
> +{
> + MshvState *s = MSHV_STATE(as);
> + CPUState *cpu;
> + int ret, vm_fd = s->vm;
> +
> + ret = mshv_clock_prepare_resume(vm_fd);
> + if (ret < 0) {
> + error_report("Failed to prepare clock for resume");
> + abort();
> + }
> +
> + CPU_FOREACH(cpu) {
> + if (!cpu->vcpu_dirty) {
> + continue;
> + }
> + cpu_synchronize_post_init(cpu);
> + }
> +
> + ret = mshv_clock_finish_resume(vm_fd);
> + if (ret < 0) {
> + error_report("Failed to finish clock for resume");
> + abort();
> + }
> +}
> +
> static void do_mshv_cpu_synchronize(CPUState *cpu, run_on_cpu_data arg)
> {
> if (!cpu->vcpu_dirty) {
> @@ -962,6 +992,7 @@ static void mshv_accel_class_init(ObjectClass *oc, const void *data)
> ac->name = "MSHV";
> ac->init_machine = mshv_init;
> ac->allowed = &mshv_allowed;
> + ac->pre_resume_vm = mshv_pre_resume_vm;
> }
>
> static void mshv_accel_instance_init(Object *obj)
> diff --git a/hw/i386/mshv/clock.c b/hw/i386/mshv/clock.c
> index 02c586503a..2a03d3cef9 100644
> --- a/hw/i386/mshv/clock.c
> +++ b/hw/i386/mshv/clock.c
> @@ -29,6 +29,7 @@
> typedef struct MshvClockState {
> uint64_t ref_time;
> bool ref_time_pending;
> + bool time_frozen;
> } MshvClockState;
>
> static MshvClockState mshv_clock;
> @@ -110,52 +111,85 @@ static int mshv_set_time_freeze(int vm_fd, int freeze)
> return 0;
> }
>
> -static void mshv_clock_vm_state_change(void *opaque, bool running,
> - RunState state)
> -{
> - MshvClockState *s = opaque;
> - int vm_fd = mshv_state->vm;
> +static int ensure_time_frozen(int vm_fd) {
> int ret;
>
> - if (running) {
> - /* Skip if we have nothing to restore, e.g. on initial boot. */
> - if (!s->ref_time_pending) {
> - return;
> - }
> + /* Ensure time is frozen */
> + if (mshv_clock.time_frozen) {
> + return 0;
> + }
>
> - ret = mshv_set_time_freeze(vm_fd, 1);
> - if (ret < 0) {
> - error_report("Failed to freeze partition time on resume");
> - abort();
> - }
> + ret = mshv_set_time_freeze(vm_fd, 1);
> + if (ret < 0) {
> + error_report("Failed to freeze partition");
> + return -1;
> + }
> + mshv_clock.time_frozen = true;
>
> + return 0;
> +}
> +
> +int mshv_clock_prepare_resume(int vm_fd) {
> + return ensure_time_frozen(vm_fd);
> +}
> +
> +int mshv_clock_finish_resume(int vm_fd) {
> + int ret;
> + MshvClockState *s = &mshv_clock;
> +
> + assert(mshv_clock.time_frozen);
> +
> + /* Skip if we have nothing to restore, e.g. on initial boot. */
> + if (s->ref_time_pending) {
> /* INVARIANT: reference time can only be written if time is frozen. */
> ret = mshv_set_reference_time(vm_fd, s->ref_time);
> if (ret < 0) {
> error_report("Failed to restore reference time on resume");
> - abort();
> + return -1;
> }
> + s->ref_time_pending = false;
> + }
>
> - if (mshv_set_time_freeze(vm_fd, 0) < 0) {
> - error_report("Failed to unfreeze partition time on resume");
> - abort();
> - }
> + ret = mshv_set_time_freeze(vm_fd, 0);
> + if (ret < 0) {
> + error_report("Failed to thaw partition");
> + return -1;
> + }
> + mshv_clock.time_frozen = false;
>
> - s->ref_time_pending = false;
> - } else {
> - /* Skip if we already have a to-be-set ref time */
> - if (s->ref_time_pending) {
> - return;
> - }
> + return 0;
> +}
>
> - ret = mshv_get_reference_time(vm_fd, &s->ref_time);
> - if (ret < 0) {
> - error_report("Failed to capture reference time on stop");
> - abort();
> - }
> +static void mshv_clock_vm_state_change(void *opaque, bool running,
> + RunState state)
> +{
> + MshvClockState *s = opaque;
> + int vm_fd = mshv_state->vm;
> + int ret;
>
> - s->ref_time_pending = true;
> + if (running) {
> + return;
> }
> +
> + /* Ensure the time if frozen before we capture the reference time. */
> + ret = ensure_time_frozen(vm_fd);
> + if (ret < 0) {
> + error_report("Failed to freeze partition time on stop");
> + abort();
> + }
> +
> + /* Skip if we already have a to-be-set ref time */
> + if (s->ref_time_pending) {
> + return;
> + }
> +
> + ret = mshv_get_reference_time(vm_fd, &s->ref_time);
> + if (ret < 0) {
> + error_report("Failed to capture reference time on stop");
> + abort();
> + }
> +
> + s->ref_time_pending = true;
> }
>
> /*
> @@ -182,8 +216,19 @@ static const VMStateDescription vmstate_mshv_clock = {
> },
> };
>
> -void mshv_clock_init(void)
> +int mshv_clock_init(int vm_fd)
> {
> + int ret;
> +
> + ret = mshv_set_time_freeze(vm_fd, 1);
> + if (ret < 0) {
> + error_report("Failed to freeze partition time on init");
> + return -1;
> + }
> + mshv_clock.time_frozen = true;
> +
> vmstate_register(NULL, 0, &vmstate_mshv_clock, &mshv_clock);
> qemu_add_vm_change_state_handler(mshv_clock_vm_state_change, &mshv_clock);
> +
> + return 0;
> }
> diff --git a/include/system/mshv.h b/include/system/mshv.h
> index f98ddff9b5..864f2aa34d 100644
> --- a/include/system/mshv.h
> +++ b/include/system/mshv.h
> @@ -58,7 +58,9 @@ DECLARE_INSTANCE_CHECKER(MshvState, MSHV_STATE,
> extern MshvState *mshv_state;
>
> /* clock (partition reference time) */
> -void mshv_clock_init(void);
> +int mshv_clock_init(int vm_fd);
> +int mshv_clock_prepare_resume(int vm_fd);
> +int mshv_clock_finish_resume(int vm_fd);
>
> /* interrupt */
> int mshv_request_interrupt(MshvState *mshv_state, uint32_t interrupt_type, uint32_t vector,
> --
> 2.34.1
Reviewed-by: Doru Blânzeanu <dblanzeanu@linux.microsoft.com>
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] accel/mshv: freeze time during TSC MSR write
2026-11-09 16:22 ` Doru Blânzeanu
@ 2026-11-11 19:36 ` Magnus Kulke
0 siblings, 0 replies; 3+ messages in thread
From: Magnus Kulke @ 2026-11-11 19:36 UTC (permalink / raw)
To: Doru Blânzeanu
Cc: qemu-devel, Michael S. Tsirkin, Paolo Bonzini, Wei Liu, Wei Liu,
Feng Liang, Richard Henderson, Doru Blânzeanu
On Mon, Nov 09, 2026 at 06:22:16PM +0200, Doru Blânzeanu wrote:
> On Fri, Nov 06, 2026 at 03:39:28PM +0100, Magnus Kulke wrote:
> > A regression was introduced when the HV_X64_REGISTER_TSC MSR state is
> > being written to the hypervisor as part of the migration framework. If
> > the MSR is written without the time being frozen, the tsc_page (a
> > hyper-v enlightenment) is zeroed out and cannot be used by a guest,
> > which results in a performance regression, because the guest falls back
> > to costly reads of HV_X64_MSR_TIME_REF_COUNT.
> >
> > An implementation of pre_resume_vm hook was added to handle the clock
> > lifecycle, relying on the dirty_vcpu state to avoid redundant state
> > writes.
> >
> > Fixes: d540dcc5e28c (target/i386/mshv: migrate MSRs)
> >
> > Signed-off-by: Magnus Kulke <magnuskulke@linux.microsoft.com>
> > ---
> > accel/mshv/mshv-all.c | 33 ++++++++++++-
> > hw/i386/mshv/clock.c | 111 +++++++++++++++++++++++++++++-------------
> > include/system/mshv.h | 4 +-
> > 3 files changed, 113 insertions(+), 35 deletions(-)
> >
> > diff --git a/accel/mshv/mshv-all.c b/accel/mshv/mshv-all.c
> > index d820a67b95..ae7577d407 100644
> > --- a/accel/mshv/mshv-all.c
> > +++ b/accel/mshv/mshv-all.c
> > @@ -34,6 +34,7 @@
> > #include "accel/accel-cpu-ops.h"
> > #include "exec/cpu-common.h"
> > #include "system/cpus.h"
> > +#include "system/hw_accel.h"
> > #include "system/runstate.h"
> > #include "system/accel-blocker.h"
> > #include "system/address-spaces.h"
> > @@ -578,7 +579,10 @@ static int mshv_init(AccelState *as, MachineState *ms)
> >
> > register_savevm_live("mshv", 0, 1, &savevm_mshv, s);
> >
> > - mshv_clock_init();
> > + ret = mshv_clock_init(vm_fd);
> > + if (ret < 0) {
> > + return -1;
> > + }
> >
> > return 0;
> > }
> > @@ -927,6 +931,32 @@ static void mshv_cpu_synchronize_pre_loadvm(CPUState *cpu)
> > run_on_cpu(cpu, do_mshv_cpu_synchronize_pre_loadvm, RUN_ON_CPU_NULL);
> > }
> >
> > +static void mshv_pre_resume_vm(AccelState *as, bool step_pending)
> > +{
> > + MshvState *s = MSHV_STATE(as);
> > + CPUState *cpu;
> > + int ret, vm_fd = s->vm;
> > +
> > + ret = mshv_clock_prepare_resume(vm_fd);
> > + if (ret < 0) {
> > + error_report("Failed to prepare clock for resume");
> > + abort();
> > + }
> > +
> > + CPU_FOREACH(cpu) {
> > + if (!cpu->vcpu_dirty) {
> > + continue;
> > + }
> > + cpu_synchronize_post_init(cpu);
> > + }
> > +
> > + ret = mshv_clock_finish_resume(vm_fd);
> > + if (ret < 0) {
> > + error_report("Failed to finish clock for resume");
> > + abort();
> > + }
> > +}
> > +
> > static void do_mshv_cpu_synchronize(CPUState *cpu, run_on_cpu_data arg)
> > {
> > if (!cpu->vcpu_dirty) {
> > @@ -962,6 +992,7 @@ static void mshv_accel_class_init(ObjectClass *oc, const void *data)
> > ac->name = "MSHV";
> > ac->init_machine = mshv_init;
> > ac->allowed = &mshv_allowed;
> > + ac->pre_resume_vm = mshv_pre_resume_vm;
> > }
> >
> > static void mshv_accel_instance_init(Object *obj)
> > diff --git a/hw/i386/mshv/clock.c b/hw/i386/mshv/clock.c
> > index 02c586503a..2a03d3cef9 100644
> > --- a/hw/i386/mshv/clock.c
> > +++ b/hw/i386/mshv/clock.c
> > @@ -29,6 +29,7 @@
> > typedef struct MshvClockState {
> > uint64_t ref_time;
> > bool ref_time_pending;
> > + bool time_frozen;
> > } MshvClockState;
> >
> > static MshvClockState mshv_clock;
> > @@ -110,52 +111,85 @@ static int mshv_set_time_freeze(int vm_fd, int freeze)
> > return 0;
> > }
> >
> > -static void mshv_clock_vm_state_change(void *opaque, bool running,
> > - RunState state)
> > -{
> > - MshvClockState *s = opaque;
> > - int vm_fd = mshv_state->vm;
> > +static int ensure_time_frozen(int vm_fd) {
> > int ret;
> >
> > - if (running) {
> > - /* Skip if we have nothing to restore, e.g. on initial boot. */
> > - if (!s->ref_time_pending) {
> > - return;
> > - }
> > + /* Ensure time is frozen */
> > + if (mshv_clock.time_frozen) {
> > + return 0;
> > + }
> >
> > - ret = mshv_set_time_freeze(vm_fd, 1);
> > - if (ret < 0) {
> > - error_report("Failed to freeze partition time on resume");
> > - abort();
> > - }
> > + ret = mshv_set_time_freeze(vm_fd, 1);
> > + if (ret < 0) {
> > + error_report("Failed to freeze partition");
> > + return -1;
> > + }
> > + mshv_clock.time_frozen = true;
> >
> > + return 0;
> > +}
> > +
> > +int mshv_clock_prepare_resume(int vm_fd) {
> > + return ensure_time_frozen(vm_fd);
> > +}
> > +
> > +int mshv_clock_finish_resume(int vm_fd) {
> > + int ret;
> > + MshvClockState *s = &mshv_clock;
> > +
> > + assert(mshv_clock.time_frozen);
> > +
> > + /* Skip if we have nothing to restore, e.g. on initial boot. */
> > + if (s->ref_time_pending) {
> > /* INVARIANT: reference time can only be written if time is frozen. */
> > ret = mshv_set_reference_time(vm_fd, s->ref_time);
> > if (ret < 0) {
> > error_report("Failed to restore reference time on resume");
> > - abort();
> > + return -1;
> > }
> > + s->ref_time_pending = false;
> > + }
> >
> > - if (mshv_set_time_freeze(vm_fd, 0) < 0) {
> > - error_report("Failed to unfreeze partition time on resume");
> > - abort();
> > - }
> > + ret = mshv_set_time_freeze(vm_fd, 0);
> > + if (ret < 0) {
> > + error_report("Failed to thaw partition");
> > + return -1;
> > + }
> > + mshv_clock.time_frozen = false;
> >
> > - s->ref_time_pending = false;
> > - } else {
> > - /* Skip if we already have a to-be-set ref time */
> > - if (s->ref_time_pending) {
> > - return;
> > - }
> > + return 0;
> > +}
> >
> > - ret = mshv_get_reference_time(vm_fd, &s->ref_time);
> > - if (ret < 0) {
> > - error_report("Failed to capture reference time on stop");
> > - abort();
> > - }
> > +static void mshv_clock_vm_state_change(void *opaque, bool running,
> > + RunState state)
> > +{
> > + MshvClockState *s = opaque;
> > + int vm_fd = mshv_state->vm;
> > + int ret;
> >
> > - s->ref_time_pending = true;
> > + if (running) {
> > + return;
> > }
> > +
> > + /* Ensure the time if frozen before we capture the reference time. */
> > + ret = ensure_time_frozen(vm_fd);
> > + if (ret < 0) {
> > + error_report("Failed to freeze partition time on stop");
> > + abort();
> > + }
> > +
> > + /* Skip if we already have a to-be-set ref time */
> > + if (s->ref_time_pending) {
> > + return;
> > + }
> > +
> > + ret = mshv_get_reference_time(vm_fd, &s->ref_time);
> > + if (ret < 0) {
> > + error_report("Failed to capture reference time on stop");
> > + abort();
> > + }
> > +
> > + s->ref_time_pending = true;
> > }
> >
> > /*
> > @@ -182,8 +216,19 @@ static const VMStateDescription vmstate_mshv_clock = {
> > },
> > };
> >
> > -void mshv_clock_init(void)
> > +int mshv_clock_init(int vm_fd)
> > {
> > + int ret;
> > +
> > + ret = mshv_set_time_freeze(vm_fd, 1);
> > + if (ret < 0) {
> > + error_report("Failed to freeze partition time on init");
> > + return -1;
> > + }
> > + mshv_clock.time_frozen = true;
> > +
> > vmstate_register(NULL, 0, &vmstate_mshv_clock, &mshv_clock);
> > qemu_add_vm_change_state_handler(mshv_clock_vm_state_change, &mshv_clock);
> > +
> > + return 0;
> > }
> > diff --git a/include/system/mshv.h b/include/system/mshv.h
> > index f98ddff9b5..864f2aa34d 100644
> > --- a/include/system/mshv.h
> > +++ b/include/system/mshv.h
> > @@ -58,7 +58,9 @@ DECLARE_INSTANCE_CHECKER(MshvState, MSHV_STATE,
> > extern MshvState *mshv_state;
> >
> > /* clock (partition reference time) */
> > -void mshv_clock_init(void);
> > +int mshv_clock_init(int vm_fd);
> > +int mshv_clock_prepare_resume(int vm_fd);
> > +int mshv_clock_finish_resume(int vm_fd);
> >
> > /* interrupt */
> > int mshv_request_interrupt(MshvState *mshv_state, uint32_t interrupt_type, uint32_t vector,
> > --
> > 2.34.1
>
> Reviewed-by: Doru Blânzeanu <dblanzeanu@linux.microsoft.com>
queued in pull-20261111
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-11-11 19:37 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-06 14:39 [PATCH] accel/mshv: freeze time during TSC MSR write Magnus Kulke
2026-11-09 16:22 ` Doru Blânzeanu
2026-11-11 19:36 ` Magnus Kulke
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.