whpx: xsave support
Signed-off-by: Mohamed Mediouni <mohamed@unpredictable.fr> Link: https://lore.kernel.org/r/20260422214225.2242-30-mohamed@unpredictable.fr Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Mohamed Mediouni committed
Apr 22, 2026 at 23:42 UTC
cfaa3b6c95972359c5a7299649b0f3408f03eeeb
3 files changed
+293
-104
include/system/whpx-internal.h
+16
@@ -99,6 +99,22 @@ void whpx_apic_get(APICCommonState *s);
99
UINT32 StateSize)) \
100
X(HRESULT, WHvResetPartition, \
101
(WHV_PARTITION_HANDLE Partition)) \
102
+ X(HRESULT, WHvGetVirtualProcessorXsaveState, \
103
+ (WHV_PARTITION_HANDLE Partition, UINT32 VpIndex, \
104
+ PVOID Buffer, \
105
+ UINT32 BufferSizeInBytes, UINT32 *BytesWritten)) \
106
+ X(HRESULT, WHvSetVirtualProcessorXsaveState, \
107
+ (WHV_PARTITION_HANDLE Partition, UINT32 VpIndex, \
108
+ PVOID Buffer, \
109
+ UINT32 BufferSizeInBytes)) \
110
+ X(HRESULT, WHvGetVirtualProcessorState, \
111
+ (WHV_PARTITION_HANDLE Partition, UINT32 VpIndex, \
112
+ WHV_VIRTUAL_PROCESSOR_STATE_TYPE StateType, PVOID Buffer, \
113
+ UINT32 BufferSizeInBytes, UINT32 *BytesWritten)) \
114
+ X(HRESULT, WHvSetVirtualProcessorState, \
115
+ (WHV_PARTITION_HANDLE Partition, UINT32 VpIndex, \
116
+ WHV_VIRTUAL_PROCESSOR_STATE_TYPE StateType, PVOID Buffer, \
117
+ UINT32 BufferSizeInBytes)) \
118
LIST_WINHVPLATFORM_FUNCTIONS_SUPPLEMENTAL_ARCH(X)
119
120
#define WHP_DEFINE_TYPE(return_type, function_name, signature) \
target/i386/meson.build
+1
-1
@@ -10,7 +10,7 @@ i386_ss.add(when: 'CONFIG_SEV', if_true: files('host-cpu.c', 'confidential-guest
10
# x86 cpu type
11
i386_ss.add(when: 'CONFIG_KVM', if_true: files('xsave_helper.c', 'host-cpu.c'))
12
i386_ss.add(when: 'CONFIG_HVF', if_true: files('xsave_helper.c', 'host-cpu.c'))
13
-i386_ss.add(when: 'CONFIG_WHPX', if_true: files('host-cpu.c'))
13
+i386_ss.add(when: 'CONFIG_WHPX', if_true: files('xsave_helper.c', 'host-cpu.c'))
14
i386_ss.add(when: 'CONFIG_NVMM', if_true: files('host-cpu.c'))
15
i386_ss.add(when: 'CONFIG_MSHV', if_true: files('host-cpu.c'))
16
target/i386/whpx/whpx-all.c
+276
-103
@@ -10,6 +10,7 @@
10
11
#include "qemu/osdep.h"
12
#include "cpu.h"
13
+#include "qemu/typedefs.h"
14
#include "system/address-spaces.h"
15
#include "system/ioport.h"
16
#include "gdbstub/helpers.h"
@@ -20,6 +21,7 @@
21
#include "system/cpus.h"
22
#include "system/runstate.h"
23
#include "qemu/main-loop.h"
24
+#include "qemu/memalign.h"
25
#include "hw/core/boards.h"
26
#include "hw/intc/ioapic.h"
27
#include "hw/intc/i8259.h"
@@ -108,34 +110,6 @@ static const WHV_REGISTER_NAME whpx_register_names[] = {
110
* WHvX64RegisterDr7,
111
*/
112
111
- /* X64 Floating Point and Vector Registers */
112
- WHvX64RegisterXmm0,
113
- WHvX64RegisterXmm1,
114
- WHvX64RegisterXmm2,
115
- WHvX64RegisterXmm3,
116
- WHvX64RegisterXmm4,
117
- WHvX64RegisterXmm5,
118
- WHvX64RegisterXmm6,
119
- WHvX64RegisterXmm7,
120
- WHvX64RegisterXmm8,
121
- WHvX64RegisterXmm9,
122
- WHvX64RegisterXmm10,
123
- WHvX64RegisterXmm11,
124
- WHvX64RegisterXmm12,
125
- WHvX64RegisterXmm13,
126
- WHvX64RegisterXmm14,
127
- WHvX64RegisterXmm15,
128
- WHvX64RegisterFpMmx0,
129
- WHvX64RegisterFpMmx1,
130
- WHvX64RegisterFpMmx2,
131
- WHvX64RegisterFpMmx3,
132
- WHvX64RegisterFpMmx4,
133
- WHvX64RegisterFpMmx5,
134
- WHvX64RegisterFpMmx6,
135
- WHvX64RegisterFpMmx7,
136
- WHvX64RegisterFpControlStatus,
137
- WHvX64RegisterXmmControlStatus,
138
-
113
/* X64 MSRs */
114
WHvX64RegisterEfer,
115
#ifdef TARGET_X86_64
@@ -182,6 +156,36 @@ static const WHV_REGISTER_NAME whpx_register_names_for_vmexit[] = {
156
WHvX64RegisterR15,
157
};
158
159
+static const WHV_REGISTER_NAME whpx_register_names_legacy_fp[] = {
160
+ /* X64 Floating Point and Vector Registers (non-xsave) */
161
+ WHvX64RegisterXmm0,
162
+ WHvX64RegisterXmm1,
163
+ WHvX64RegisterXmm2,
164
+ WHvX64RegisterXmm3,
165
+ WHvX64RegisterXmm4,
166
+ WHvX64RegisterXmm5,
167
+ WHvX64RegisterXmm6,
168
+ WHvX64RegisterXmm7,
169
+ WHvX64RegisterXmm8,
170
+ WHvX64RegisterXmm9,
171
+ WHvX64RegisterXmm10,
172
+ WHvX64RegisterXmm11,
173
+ WHvX64RegisterXmm12,
174
+ WHvX64RegisterXmm13,
175
+ WHvX64RegisterXmm14,
176
+ WHvX64RegisterXmm15,
177
+ WHvX64RegisterFpMmx0,
178
+ WHvX64RegisterFpMmx1,
179
+ WHvX64RegisterFpMmx2,
180
+ WHvX64RegisterFpMmx3,
181
+ WHvX64RegisterFpMmx4,
182
+ WHvX64RegisterFpMmx5,
183
+ WHvX64RegisterFpMmx6,
184
+ WHvX64RegisterFpMmx7,
185
+ WHvX64RegisterFpControlStatus,
186
+ WHvX64RegisterXmmControlStatus,
187
+};
188
+
189
struct whpx_register_set {
190
WHV_REGISTER_VALUE values[RTL_NUMBER_OF(whpx_register_names)];
191
};
@@ -392,6 +396,123 @@ static int whpx_set_tsc(CPUState *cpu)
396
return 0;
397
}
398
399
+static bool whpx_is_xsave_enabled(CPUState *cpu)
400
+{
401
+ CPUX86State *env = &X86_CPU(cpu)->env;
402
+ return env->cr[4] & CR4_OSXSAVE_MASK;
403
+}
404
+
405
+static size_t whpx_get_xsave_max_len(void)
406
+{
407
+ return whpx_get_supported_cpuid(0xd, 0, R_ECX);
408
+}
409
+
410
+static int whpx_set_xsave_state(const CPUState *cpu)
411
+{
412
+ struct whpx_state *whpx = &whpx_global;
413
+ X86CPU *x86cpu = X86_CPU(cpu);
414
+ CPUX86State *env = &x86cpu->env;
415
+ HRESULT hr;
416
+ void *xsavec_buf;
417
+ size_t page = qemu_real_host_page_size();
418
+ size_t xsavec_buf_len;
419
+
420
+ /* allocate and populate compacted buffer */
421
+ xsavec_buf_len = whpx_get_xsave_max_len();
422
+ xsavec_buf = qemu_memalign(page, xsavec_buf_len);
423
+
424
+ /* save registers to standard format buffer */
425
+ x86_cpu_xsave_all_areas(x86cpu, env->xsave_buf, env->xsave_buf_len);
426
+
427
+ /* store compacted version of xsave area in xsavec_buf */
428
+ compact_xsave_area(env, xsavec_buf, xsavec_buf_len);
429
+
430
+ if (!whpx_is_legacy_os()) {
431
+ hr = whp_dispatch.WHvSetVirtualProcessorState(
432
+ whpx->partition, cpu->cpu_index,
433
+ WHvVirtualProcessorStateTypeXsaveState,
434
+ xsavec_buf,
435
+ xsavec_buf_len);
436
+ } else {
437
+ hr = whp_dispatch.WHvSetVirtualProcessorXsaveState(
438
+ whpx->partition, cpu->cpu_index,
439
+ xsavec_buf,
440
+ xsavec_buf_len);
441
+ }
442
+
443
+ qemu_vfree(xsavec_buf);
444
+ if (FAILED(hr)) {
445
+ error_report("WHPX: Failed to get virtual processor context, hr=%08lx",
446
+ hr);
447
+ }
448
+
449
+ return 0;
450
+}
451
+
452
+static void whpx_set_legacy_fp_registers(CPUState *cpu, WHPXStateLevel level)
453
+{
454
+ struct whpx_state *whpx = &whpx_global;
455
+ X86CPU *x86_cpu = X86_CPU(cpu);
456
+ CPUX86State *env = &x86_cpu->env;
457
+ struct whpx_register_set vcxt;
458
+ HRESULT hr;
459
+ int idx = 0;
460
+ int i;
461
+ int idx_next;
462
+
463
+ assert(cpu_is_stopped(cpu) || qemu_cpu_is_self(cpu));
464
+
465
+ /* 16 XMM registers */
466
+ assert(whpx_register_names_legacy_fp[idx] == WHvX64RegisterXmm0);
467
+ idx_next = idx + 16;
468
+ for (i = 0; i < sizeof(env->xmm_regs) / sizeof(ZMMReg); i += 1, idx += 1) {
469
+ vcxt.values[idx].Reg128.Low64 = env->xmm_regs[i].ZMM_Q(0);
470
+ vcxt.values[idx].Reg128.High64 = env->xmm_regs[i].ZMM_Q(1);
471
+ }
472
+ idx = idx_next;
473
+
474
+ /* 8 FP registers */
475
+ assert(whpx_register_names_legacy_fp[idx] == WHvX64RegisterFpMmx0);
476
+ for (i = 0; i < 8; i += 1, idx += 1) {
477
+ vcxt.values[idx].Fp.AsUINT128.Low64 = env->fpregs[i].mmx.MMX_Q(0);
478
+ /* vcxt.values[idx].Fp.AsUINT128.High64 =
479
+ env->fpregs[i].mmx.MMX_Q(1);
480
+ */
481
+ }
482
+
483
+ /* FP control status register */
484
+ assert(whpx_register_names_legacy_fp[idx] == WHvX64RegisterFpControlStatus);
485
+ vcxt.values[idx].FpControlStatus.FpControl = env->fpuc;
486
+ vcxt.values[idx].FpControlStatus.FpStatus =
487
+ (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
488
+ vcxt.values[idx].FpControlStatus.FpTag = 0;
489
+ for (i = 0; i < 8; ++i) {
490
+ vcxt.values[idx].FpControlStatus.FpTag |= (!env->fptags[i]) << i;
491
+ }
492
+ vcxt.values[idx].FpControlStatus.Reserved = 0;
493
+ vcxt.values[idx].FpControlStatus.LastFpOp = env->fpop;
494
+ vcxt.values[idx].FpControlStatus.LastFpRip = env->fpip;
495
+ idx += 1;
496
+
497
+ /* XMM control status register */
498
+ assert(whpx_register_names_legacy_fp[idx] == WHvX64RegisterXmmControlStatus);
499
+ vcxt.values[idx].XmmControlStatus.LastFpRdp = 0;
500
+ vcxt.values[idx].XmmControlStatus.XmmStatusControl = env->mxcsr;
501
+ vcxt.values[idx].XmmControlStatus.XmmStatusControlMask = 0x0000ffff;
502
+ idx += 1;
503
+
504
+ hr = whp_dispatch.WHvSetVirtualProcessorRegisters(
505
+ whpx->partition, cpu->cpu_index,
506
+ whpx_register_names_legacy_fp,
507
+ idx,
508
+ &vcxt.values[0]);
509
+
510
+ if (FAILED(hr)) {
511
+ error_report("WHPX: Failed to set virtual processor context, hr=%08lx",
512
+ hr);
513
+ }
514
+}
515
+
516
void whpx_set_registers(CPUState *cpu, WHPXStateLevel level)
517
{
518
struct whpx_state *whpx = &whpx_global;
@@ -491,45 +612,11 @@ void whpx_set_registers(CPUState *cpu, WHPXStateLevel level)
612
*/
613
whpx_set_xcrs(cpu);
614
494
- /* 16 XMM registers */
495
- assert(whpx_register_names[idx] == WHvX64RegisterXmm0);
496
- idx_next = idx + 16;
497
- for (i = 0; i < sizeof(env->xmm_regs) / sizeof(ZMMReg); i += 1, idx += 1) {
498
- vcxt.values[idx].Reg128.Low64 = env->xmm_regs[i].ZMM_Q(0);
499
- vcxt.values[idx].Reg128.High64 = env->xmm_regs[i].ZMM_Q(1);
500
- }
501
- idx = idx_next;
502
-
503
- /* 8 FP registers */
504
- assert(whpx_register_names[idx] == WHvX64RegisterFpMmx0);
505
- for (i = 0; i < 8; i += 1, idx += 1) {
506
- vcxt.values[idx].Fp.AsUINT128.Low64 = env->fpregs[i].mmx.MMX_Q(0);
507
- /* vcxt.values[idx].Fp.AsUINT128.High64 =
508
- env->fpregs[i].mmx.MMX_Q(1);
509
- */
510
- }
511
-
512
- /* FP control status register */
513
- assert(whpx_register_names[idx] == WHvX64RegisterFpControlStatus);
514
- vcxt.values[idx].FpControlStatus.FpControl = env->fpuc;
515
- vcxt.values[idx].FpControlStatus.FpStatus =
516
- (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
517
- vcxt.values[idx].FpControlStatus.FpTag = 0;
518
- for (i = 0; i < 8; ++i) {
519
- vcxt.values[idx].FpControlStatus.FpTag |= (!env->fptags[i]) << i;
615
+ if (whpx_is_xsave_enabled(cpu)) {
616
+ whpx_set_xsave_state(cpu);
617
+ } else {
618
+ whpx_set_legacy_fp_registers(cpu, level);
619
}
521
- vcxt.values[idx].FpControlStatus.Reserved = 0;
522
- vcxt.values[idx].FpControlStatus.LastFpOp = env->fpop;
523
- vcxt.values[idx].FpControlStatus.LastFpRip = env->fpip;
524
- idx += 1;
525
-
526
- /* XMM control status register */
527
- assert(whpx_register_names[idx] == WHvX64RegisterXmmControlStatus);
528
- vcxt.values[idx].XmmControlStatus.LastFpRdp = 0;
529
- vcxt.values[idx].XmmControlStatus.XmmStatusControl = env->mxcsr;
530
- vcxt.values[idx].XmmControlStatus.XmmStatusControlMask = 0x0000ffff;
531
- idx += 1;
532
-
620
/* MSRs */
621
assert(whpx_register_names[idx] == WHvX64RegisterEfer);
622
vcxt.values[idx++].Reg64 = env->efer;
@@ -662,6 +749,110 @@ static void whpx_get_registers_for_vmexit(CPUState *cpu, WHPXStateLevel level)
749
x86_update_hflags(env);
750
}
751
752
+static void whpx_get_legacy_fp_registers(CPUState *cpu, WHPXStateLevel level)
753
+{
754
+ struct whpx_state *whpx = &whpx_global;
755
+ X86CPU *x86_cpu = X86_CPU(cpu);
756
+ CPUX86State *env = &x86_cpu->env;
757
+ struct whpx_register_set vcxt;
758
+ HRESULT hr;
759
+ int i;
760
+ int idx;
761
+ int idx_next;
762
+
763
+ assert(cpu_is_stopped(cpu) || qemu_cpu_is_self(cpu));
764
+
765
+ hr = whp_dispatch.WHvGetVirtualProcessorRegisters(
766
+ whpx->partition, cpu->cpu_index,
767
+ whpx_register_names_legacy_fp,
768
+ RTL_NUMBER_OF(whpx_register_names_legacy_fp),
769
+ &vcxt.values[0]);
770
+
771
+ if (FAILED(hr)) {
772
+ error_report("WHPX: Failed to get virtual processor context, hr=%08lx",
773
+ hr);
774
+ }
775
+
776
+ idx = 0;
777
+ /* 16 XMM registers */
778
+ assert(whpx_register_names_legacy_fp[idx] == WHvX64RegisterXmm0);
779
+ idx_next = idx + 16;
780
+ for (i = 0; i < sizeof(env->xmm_regs) / sizeof(ZMMReg); i += 1, idx += 1) {
781
+ env->xmm_regs[i].ZMM_Q(0) = vcxt.values[idx].Reg128.Low64;
782
+ env->xmm_regs[i].ZMM_Q(1) = vcxt.values[idx].Reg128.High64;
783
+ }
784
+ idx = idx_next;
785
+
786
+ /* 8 FP registers */
787
+ assert(whpx_register_names_legacy_fp[idx] == WHvX64RegisterFpMmx0);
788
+ for (i = 0; i < 8; i += 1, idx += 1) {
789
+ env->fpregs[i].mmx.MMX_Q(0) = vcxt.values[idx].Fp.AsUINT128.Low64;
790
+ /* env->fpregs[i].mmx.MMX_Q(1) =
791
+ vcxt.values[idx].Fp.AsUINT128.High64;
792
+ */
793
+ }
794
+
795
+ /* FP control status register */
796
+ assert(whpx_register_names_legacy_fp[idx] == WHvX64RegisterFpControlStatus);
797
+ env->fpuc = vcxt.values[idx].FpControlStatus.FpControl;
798
+ env->fpstt = (vcxt.values[idx].FpControlStatus.FpStatus >> 11) & 0x7;
799
+ env->fpus = vcxt.values[idx].FpControlStatus.FpStatus & ~0x3800;
800
+ for (i = 0; i < 8; ++i) {
801
+ env->fptags[i] = !((vcxt.values[idx].FpControlStatus.FpTag >> i) & 1);
802
+ }
803
+ env->fpop = vcxt.values[idx].FpControlStatus.LastFpOp;
804
+ env->fpip = vcxt.values[idx].FpControlStatus.LastFpRip;
805
+ idx += 1;
806
+
807
+ /* XMM control status register */
808
+ assert(whpx_register_names_legacy_fp[idx] == WHvX64RegisterXmmControlStatus);
809
+ env->mxcsr = vcxt.values[idx].XmmControlStatus.XmmStatusControl;
810
+ idx += 1;
811
+}
812
+
813
+static int whpx_get_xsave_state(CPUState *cpu)
814
+{
815
+ struct whpx_state *whpx = &whpx_global;
816
+ X86CPU *x86cpu = X86_CPU(cpu);
817
+ CPUX86State *env = &x86cpu->env;
818
+ int ret;
819
+ HRESULT hr;
820
+ void *xsavec_buf;
821
+ const size_t page = qemu_real_host_page_size();
822
+ size_t xsavec_buf_len = whpx_get_xsave_max_len();
823
+ UINT32 bytes_written;
824
+
825
+ xsavec_buf = qemu_memalign(page, xsavec_buf_len);
826
+ memset(xsavec_buf, 0, xsavec_buf_len);
827
+
828
+ if (!whpx_is_legacy_os()) {
829
+ hr = whp_dispatch.WHvGetVirtualProcessorState(
830
+ whpx->partition, cpu->cpu_index,
831
+ WHvVirtualProcessorStateTypeXsaveState,
832
+ xsavec_buf,
833
+ xsavec_buf_len, &bytes_written);
834
+ } else {
835
+ hr = whp_dispatch.WHvGetVirtualProcessorXsaveState(
836
+ whpx->partition, cpu->cpu_index,
837
+ xsavec_buf,
838
+ xsavec_buf_len, &bytes_written);
839
+ }
840
+ if (FAILED(hr) || bytes_written == 0) {
841
+ error_report("failed to get xsave state: %s", strerror(errno));
842
+ return -errno;
843
+ }
844
+
845
+ ret = decompact_xsave_area(xsavec_buf, xsavec_buf_len, env);
846
+ qemu_vfree(xsavec_buf);
847
+ if (ret < 0) {
848
+ error_report("failed to decompact xsave area");
849
+ return ret;
850
+ }
851
+ x86_cpu_xrstor_all_areas(x86cpu, env->xsave_buf, env->xsave_buf_len);
852
+
853
+ return 0;
854
+}
855
+
856
void whpx_get_registers(CPUState *cpu, WHPXStateLevel level)
857
{
858
struct whpx_state *whpx = &whpx_global;
@@ -758,40 +949,11 @@ void whpx_get_registers(CPUState *cpu, WHPXStateLevel level)
949
*/
950
whpx_get_xcrs(cpu);
951
761
- /* 16 XMM registers */
762
- assert(whpx_register_names[idx] == WHvX64RegisterXmm0);
763
- idx_next = idx + 16;
764
- for (i = 0; i < sizeof(env->xmm_regs) / sizeof(ZMMReg); i += 1, idx += 1) {
765
- env->xmm_regs[i].ZMM_Q(0) = vcxt.values[idx].Reg128.Low64;
766
- env->xmm_regs[i].ZMM_Q(1) = vcxt.values[idx].Reg128.High64;
767
- }
768
- idx = idx_next;
769
-
770
- /* 8 FP registers */
771
- assert(whpx_register_names[idx] == WHvX64RegisterFpMmx0);
772
- for (i = 0; i < 8; i += 1, idx += 1) {
773
- env->fpregs[i].mmx.MMX_Q(0) = vcxt.values[idx].Fp.AsUINT128.Low64;
774
- /* env->fpregs[i].mmx.MMX_Q(1) =
775
- vcxt.values[idx].Fp.AsUINT128.High64;
776
- */
777
- }
778
-
779
- /* FP control status register */
780
- assert(whpx_register_names[idx] == WHvX64RegisterFpControlStatus);
781
- env->fpuc = vcxt.values[idx].FpControlStatus.FpControl;
782
- env->fpstt = (vcxt.values[idx].FpControlStatus.FpStatus >> 11) & 0x7;
783
- env->fpus = vcxt.values[idx].FpControlStatus.FpStatus & ~0x3800;
784
- for (i = 0; i < 8; ++i) {
785
- env->fptags[i] = !((vcxt.values[idx].FpControlStatus.FpTag >> i) & 1);
952
+ if (whpx_is_xsave_enabled(cpu)) {
953
+ whpx_get_xsave_state(cpu);
954
+ } else {
955
+ whpx_get_legacy_fp_registers(cpu, level);
956
}
787
- env->fpop = vcxt.values[idx].FpControlStatus.LastFpOp;
788
- env->fpip = vcxt.values[idx].FpControlStatus.LastFpRip;
789
- idx += 1;
790
-
791
- /* XMM control status register */
792
- assert(whpx_register_names[idx] == WHvX64RegisterXmmControlStatus);
793
- env->mxcsr = vcxt.values[idx].XmmControlStatus.XmmStatusControl;
794
- idx += 1;
957
958
/* MSRs */
959
assert(whpx_register_names[idx] == WHvX64RegisterEfer);
@@ -1586,6 +1748,9 @@ void whpx_arch_destroy_vcpu(CPUState *cpu)
1748
X86CPU *x86cpu = X86_CPU(cpu);
1749
CPUX86State *env = &x86cpu->env;
1750
g_free(env->emu_mmio_buf);
1751
+ qemu_vfree(env->xsave_buf);
1752
+ env->xsave_buf = NULL;
1753
+ env->xsave_buf_len = 0;
1754
}
1755
1756
/* Returns the address of the next instruction that is about to be executed. */
@@ -2446,6 +2611,9 @@ int whpx_init_vcpu(CPUState *cpu)
2611
Error *local_error = NULL;
2612
X86CPU *x86_cpu = X86_CPU(cpu);
2613
CPUX86State *env = &x86_cpu->env;
2614
+ X86XSaveHeader *header;
2615
+ size_t page_size = qemu_real_host_page_size();
2616
+ size_t xsave_len;
2617
UINT64 freq = 0;
2618
int ret;
2619
@@ -2522,6 +2690,15 @@ int whpx_init_vcpu(CPUState *cpu)
2690
qemu_add_vm_change_state_handler(whpx_cpu_update_state, env);
2691
2692
env->emu_mmio_buf = g_new(char, 4096);
2693
+ /* Initialize XSAVE buffer page-aligned */
2694
+ xsave_len = whpx_get_xsave_max_len();
2695
+ env->xsave_buf = qemu_memalign(page_size, xsave_len);
2696
+ env->xsave_buf_len = xsave_len;
2697
+ memset(env->xsave_buf, 0, env->xsave_buf_len);
2698
+
2699
+ /* we need to set the compacted format bit in xsave header for Hyper-V */
2700
+ header = (X86XSaveHeader *)(env->xsave_buf + sizeof(X86LegacyXSaveArea));
2701
+ header->xcomp_bv = header->xstate_bv | (1ULL << 63);
2702
2703
return 0;
2704
@@ -2722,10 +2899,6 @@ int whpx_accel_init(AccelState *as, MachineState *ms)
2899
error_report("WHPX: Failed to query XSAVE capability, hr=%08lx", hr);
2900
}
2901
2725
- if (!whpx_has_xsave()) {
2726
- printf("WHPX: Partition is not XSAVE capable\n");
2727
- }
2728
-
2902
memset(&prop, 0, sizeof(WHV_PARTITION_PROPERTY));
2903
prop.ProcessorCount = ms->smp.cpus;
2904
hr = whp_dispatch.WHvSetPartitionProperty(