public inbox for kvm@vger.kernel.org
 help / color / mirror / Atom feed
From: Magnus Kulke <magnuskulke@linux.microsoft.com>
To: qemu-devel@nongnu.org
Cc: kvm@vger.kernel.org, "Magnus Kulke" <magnuskulke@microsoft.com>,
	"Wei Liu" <liuwe@microsoft.com>,
	"Michael S. Tsirkin" <mst@redhat.com>,
	"Cédric Le Goater" <clg@redhat.com>,
	"Zhao Liu" <zhao1.liu@intel.com>,
	"Richard Henderson" <richard.henderson@linaro.org>,
	"Paolo Bonzini" <pbonzini@redhat.com>,
	"Wei Liu" <wei.liu@kernel.org>,
	"Magnus Kulke" <magnuskulke@linux.microsoft.com>,
	"Alex Williamson" <alex@shazbot.org>,
	"Marcel Apfelbaum" <marcel.apfelbaum@gmail.com>,
	"Philippe Mathieu-Daudé" <philmd@linaro.org>,
	"Marcelo Tosatti" <mtosatti@redhat.com>
Subject: [PATCH 31/34] target/i386/mshv: migrate XSAVE state
Date: Fri, 17 Apr 2026 12:56:15 +0200	[thread overview]
Message-ID: <20260417105618.3621-32-magnuskulke@linux.microsoft.com> (raw)
In-Reply-To: <20260417105618.3621-1-magnuskulke@linux.microsoft.com>

We implement fn's that roundtrip XSAVE state in migration. We are using
the xsave_helper routines to move individual components from CPUX86State
to an xsave_buf and then we have to compact the buffer to XSAVEC format,
which is what the hypervisor expects.

And the same applies in the other direction for restoring state from the
hypervisor.

Signed-off-by: Magnus Kulke <magnuskulke@linux.microsoft.com>
---
 target/i386/cpu.h           |   2 +-
 target/i386/mshv/mshv-cpu.c | 100 +++++++++++++++++++++++++++++++++++-
 2 files changed, 100 insertions(+), 2 deletions(-)

diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index cd5d5a5369..0f30f0dd5b 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -2272,7 +2272,7 @@ typedef struct CPUArchState {
     int64_t user_tsc_khz; /* for sanity check only */
     uint64_t apic_bus_freq;
     uint64_t tsc;
-#if defined(CONFIG_KVM) || defined(CONFIG_HVF)
+#if defined(CONFIG_KVM) || defined(CONFIG_HVF) || defined(CONFIG_MSHV)
     void *xsave_buf;
     uint32_t xsave_buf_len;
 #endif
diff --git a/target/i386/mshv/mshv-cpu.c b/target/i386/mshv/mshv-cpu.c
index 517b38a32d..5b0b8bda16 100644
--- a/target/i386/mshv/mshv-cpu.c
+++ b/target/i386/mshv/mshv-cpu.c
@@ -109,6 +109,78 @@ static enum hv_register_name FPU_REGISTER_NAMES[26] = {
 
 static int set_special_regs(const CPUState *cpu);
 
+static int get_xsave_state(CPUState *cpu)
+{
+    X86CPU *x86cpu = X86_CPU(cpu);
+    CPUX86State *env = &x86cpu->env;
+    int cpu_fd = mshv_vcpufd(cpu);
+    int ret;
+    void *xsavec_buf;
+    const size_t page = HV_HYP_PAGE_SIZE;
+    size_t xsavec_buf_len = page;
+
+    /* TODO: should properly determine xsavec size based on CPUID */
+    xsavec_buf = qemu_memalign(page, xsavec_buf_len);
+    memset(xsavec_buf, 0, xsavec_buf_len);
+
+    struct mshv_get_set_vp_state args = {
+        .type = MSHV_VP_STATE_XSAVE,
+        .buf_sz = xsavec_buf_len,
+        .buf_ptr = (uintptr_t)xsavec_buf,
+    };
+
+    ret = ioctl(cpu_fd, MSHV_GET_VP_STATE, &args);
+    if (ret < 0) {
+        error_report("failed to get xsave state: %s", strerror(errno));
+        return -errno;
+    }
+
+    ret = decompact_xsave_area(xsavec_buf, xsavec_buf_len, env);
+    g_free(xsavec_buf);
+    if (ret < 0) {
+        error_report("failed to decompact xsave area");
+        return ret;
+    }
+    x86_cpu_xrstor_all_areas(x86cpu, env->xsave_buf, env->xsave_buf_len);
+
+    return 0;
+}
+
+static int set_xsave_state(const CPUState *cpu)
+{
+    X86CPU *x86cpu = X86_CPU(cpu);
+    CPUX86State *env = &x86cpu->env;
+    int cpu_fd = mshv_vcpufd(cpu);
+    int ret;
+    void *xsavec_buf;
+    size_t page = HV_HYP_PAGE_SIZE, xsavec_buf_len;
+
+    /* allocate and populate compacted buffer */
+    xsavec_buf = qemu_memalign(page, page);
+    xsavec_buf_len = page;
+
+    /* save registers to standard format buffer */
+    x86_cpu_xsave_all_areas(x86cpu, env->xsave_buf, env->xsave_buf_len);
+
+    /* store compacted version of xsave area in xsavec_buf */
+    compact_xsave_area(env, xsavec_buf, xsavec_buf_len);
+
+    struct mshv_get_set_vp_state args = {
+        .type = MSHV_VP_STATE_XSAVE,
+        .buf_sz = xsavec_buf_len,
+        .buf_ptr = (uintptr_t)xsavec_buf,
+    };
+
+    ret = ioctl(cpu_fd, MSHV_SET_VP_STATE, &args);
+    g_free(xsavec_buf);
+    if (ret < 0) {
+        error_report("failed to set xsave state: %s", strerror(errno));
+        return -errno;
+    }
+
+    return 0;
+}
+
 static int get_lapic(CPUState *cpu)
 {
     X86CPU *x86cpu = X86_CPU(cpu);
@@ -766,6 +838,11 @@ int mshv_arch_load_vcpu_state(CPUState *cpu)
         return ret;
     }
 
+    ret = get_xsave_state(cpu);
+    if (ret < 0) {
+        return ret;
+    }
+
     ret = get_lapic(cpu);
     if (ret < 0) {
         return ret;
@@ -1258,6 +1335,11 @@ int mshv_arch_store_vcpu_state(const CPUState *cpu)
         return ret;
     }
 
+    ret = set_xsave_state(cpu);
+    if (ret < 0) {
+        return ret;
+    }
+
     /* INVARIANT: special regs (APIC_BASE) must be restored before LAPIC */
     ret = set_lapic(cpu);
     if (ret < 0) {
@@ -1786,9 +1868,10 @@ void mshv_arch_init_vcpu(CPUState *cpu)
     X86CPU *x86_cpu = X86_CPU(cpu);
     CPUX86State *env = &x86_cpu->env;
     AccelCPUState *state = cpu->accel;
-    size_t page = HV_HYP_PAGE_SIZE;
+    size_t page = HV_HYP_PAGE_SIZE, xsave_len;
     void *mem = qemu_memalign(page, 2 * page);
     int ret;
+    X86XSaveHeader *header;
 
     /* sanity check, to make sure we don't overflow the page */
     QEMU_BUILD_BUG_ON((MAX_REGISTER_COUNT
@@ -1802,6 +1885,17 @@ void mshv_arch_init_vcpu(CPUState *cpu)
 
     env->emu_mmio_buf = g_new(char, 4096);
 
+    /* Initialize XSAVE buffer page-aligned */
+    /* TODO: pick proper size based on CPUID */
+    xsave_len = page;
+    env->xsave_buf = qemu_memalign(page, xsave_len);
+    env->xsave_buf_len = xsave_len;
+    memset(env->xsave_buf, 0, env->xsave_buf_len);
+
+    /* we need to set the compacted format bit in xsave header for mshv */
+    header = (X86XSaveHeader *)(env->xsave_buf + sizeof(X86LegacyXSaveArea));
+    header->xcomp_bv = header->xstate_bv | (1ULL << 63);
+
     /*
      * TODO: populate topology info:
      * X86CPUTopoInfo *topo_info = &env->topo_info;
@@ -1826,6 +1920,10 @@ void mshv_arch_destroy_vcpu(CPUState *cpu)
     g_free(state->hvcall_args.base);
     state->hvcall_args = (MshvHvCallArgs){0};
     g_clear_pointer(&env->emu_mmio_buf, g_free);
+
+    qemu_vfree(env->xsave_buf);
+    env->xsave_buf = NULL;
+    env->xsave_buf_len = 0;
 }
 
 /*
-- 
2.34.1


  parent reply	other threads:[~2026-04-17 10:58 UTC|newest]

Thread overview: 40+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-04-17 10:55 [PATCH 00/34] Add migration support to the MSHV accelerator Magnus Kulke
2026-04-17 10:55 ` [PATCH 01/34] target/i386/mshv: use arch_load/store_reg fns Magnus Kulke
2026-04-17 10:55 ` [PATCH 02/34] target/i386/mshv: use generic FPU/xcr0 state Magnus Kulke
2026-04-17 10:55 ` [PATCH 03/34] target/i386/mshv: impl init/load/store_vcpu_state Magnus Kulke
2026-04-17 10:55 ` [PATCH 04/34] accel/accel-irq: add AccelRouteChange abstraction Magnus Kulke
2026-04-17 10:55 ` [PATCH 05/34] accel/accel-irq: add generic begin_route_changes Magnus Kulke
2026-04-17 10:55 ` [PATCH 06/34] accel/accel-irq: add generic commit_route_changes Magnus Kulke
2026-04-17 10:55 ` [PATCH 07/34] accel/mshv: add irq_routes to state Magnus Kulke
2026-04-17 10:55 ` [PATCH 08/34] accel/mshv: update s->irq_routes in add_msi_route Magnus Kulke
2026-04-17 10:55 ` [PATCH 09/34] accel/mshv: update s->irq_routes in update_msi_route Magnus Kulke
2026-04-17 10:55 ` [PATCH 10/34] accel/mshv: update s->irq_routes in release_virq Magnus Kulke
2026-04-17 10:55 ` [PATCH 11/34] accel/mshv: use s->irq_routes in commit_routes Magnus Kulke
2026-04-17 10:55 ` [PATCH 12/34] accel/mshv: reserve ioapic routes on s->irq_routes Magnus Kulke
2026-04-17 10:55 ` [PATCH 13/34] accel/mshv: remove redundant msi controller Magnus Kulke
2026-04-17 10:55 ` [PATCH 14/34] target/i386/mshv: move apic logic into own file Magnus Kulke
2026-04-17 10:55 ` [PATCH 15/34] target/i386/mshv: remove redundant apic helpers Magnus Kulke
2026-04-17 10:56 ` [PATCH 16/34] target/i386/mshv: migrate LAPIC state Magnus Kulke
2026-04-17 11:54   ` Mohamed Mediouni
2026-04-20 11:37     ` Magnus Kulke
2026-04-17 10:56 ` [PATCH 17/34] target/i386/mshv: move msr code to arch Magnus Kulke
2026-04-17 10:56 ` [PATCH 18/34] accel/mshv: store partition proc features Magnus Kulke
2026-04-17 10:56 ` [PATCH 19/34] target/i386/mshv: expose msvh_get_generic_regs Magnus Kulke
2026-04-17 10:56 ` [PATCH 20/34] target/i386/mshv: migrate MSRs Magnus Kulke
2026-04-17 10:56 ` [PATCH 21/34] target/i386/mshv: migrate MTRR MSRs Magnus Kulke
2026-04-17 10:56 ` [PATCH 22/34] target/i386/mshv: migrate Synic SINT MSRs Magnus Kulke
2026-04-17 10:56 ` [PATCH 23/34] target/i386/mshv: migrate CET/SS MSRs Magnus Kulke
2026-04-17 10:56 ` [PATCH 24/34] target/i386/mshv: migrate SIMP and SIEFP state Magnus Kulke
2026-04-17 10:56 ` [PATCH 25/34] target/i386/mshv: migrate STIMER state Magnus Kulke
2026-04-17 10:56 ` [PATCH 26/34] accel/mshv: introduce SaveVMHandler Magnus Kulke
2026-04-17 10:56 ` [PATCH 27/34] accel/mshv: write synthetic MSRs after migration Magnus Kulke
2026-04-17 10:56 ` [PATCH 28/34] accel/mshv: migrate REFERENCE_TIME Magnus Kulke
2026-04-17 10:56 ` [PATCH 29/34] target/i386/mshv: migrate pending ints/excs Magnus Kulke
2026-04-17 10:56 ` [PATCH 30/34] target/i386: add de/compaction to xsave_helper Magnus Kulke
2026-04-17 11:56   ` Mohamed Mediouni
2026-04-18 17:46   ` Mohamed Mediouni
2026-04-20 12:02     ` Magnus Kulke
2026-04-17 10:56 ` Magnus Kulke [this message]
2026-04-17 10:56 ` [PATCH 32/34] target/i386/mshv: reconstruct hflags after load Magnus Kulke
2026-04-17 10:56 ` [PATCH 33/34] target/i386/mshv: migrate MP_STATE Magnus Kulke
2026-04-17 10:56 ` [PATCH 34/34] accel/mshv: enable dirty page tracking Magnus Kulke

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260417105618.3621-32-magnuskulke@linux.microsoft.com \
    --to=magnuskulke@linux.microsoft.com \
    --cc=alex@shazbot.org \
    --cc=clg@redhat.com \
    --cc=kvm@vger.kernel.org \
    --cc=liuwe@microsoft.com \
    --cc=magnuskulke@microsoft.com \
    --cc=marcel.apfelbaum@gmail.com \
    --cc=mst@redhat.com \
    --cc=mtosatti@redhat.com \
    --cc=pbonzini@redhat.com \
    --cc=philmd@linaro.org \
    --cc=qemu-devel@nongnu.org \
    --cc=richard.henderson@linaro.org \
    --cc=wei.liu@kernel.org \
    --cc=zhao1.liu@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox