All of lore.kernel.org
 help / color / mirror / Atom feed
* [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.