diff --git a/target/i386/meson.build b/target/i386/meson.build index 80062d1d0d..b4fbf8a537 100644 --- a/target/i386/meson.build +++ b/target/i386/meson.build @@ -12,7 +12,7 @@ i386_ss.add(when: 'CONFIG_KVM', if_true: files('xsave_helper.c', 'host-cpu.c')) i386_ss.add(when: 'CONFIG_HVF', if_true: files('xsave_helper.c', 'host-cpu.c')) i386_ss.add(when: 'CONFIG_WHPX', if_true: files('xsave_helper.c', 'host-cpu.c')) i386_ss.add(when: 'CONFIG_NVMM', if_true: files('host-cpu.c')) -i386_ss.add(when: 'CONFIG_MSHV', if_true: files('host-cpu.c')) +i386_ss.add(when: 'CONFIG_MSHV', if_true: files('xsave_helper.c', 'host-cpu.c')) i386_system_ss = ss.source_set() i386_system_ss.add(files( diff --git a/target/i386/mshv/mshv-cpu.c b/target/i386/mshv/mshv-cpu.c index 9f513a0e43..bbf874f641 100644 --- a/target/i386/mshv/mshv-cpu.c +++ b/target/i386/mshv/mshv-cpu.c @@ -112,6 +112,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 void populate_fpu(const hv_register_assoc *assocs, X86CPU *x86cpu) { union hv_register_value value; @@ -717,6 +789,11 @@ int mshv_arch_load_vcpu_state(CPUState *cpu) return ret; } + ret = get_xsave_state(cpu); + if (ret < 0) { + return ret; + } + ret = get_vcpu_events(cpu); if (ret < 0) { return ret; @@ -1263,6 +1340,11 @@ int mshv_arch_store_vcpu_state(const CPUState *cpu) return ret; } + ret = set_xsave_state(cpu); + if (ret < 0) { + return ret; + } + ret = set_vcpu_events(cpu); if (ret < 0) { return ret; @@ -1817,9 +1899,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 @@ -1833,6 +1916,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; @@ -1857,6 +1951,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; } uint32_t mshv_get_supported_cpuid(uint32_t func, uint32_t idx, int reg)