From: David Woodhouse <[email protected]> XCR0/XFEM is shared between VTLs: the TLFS banks no vector state and the reference host keeps a single XCR0 (its store_vtl/load_vtl carry no XSAVE state). The planes series shares the FPU payload between twins but keeps arch.xcr0 per-vCPU, so an XSETBV in one VTL was invisible in the other: VTL1 read a stale XFEM, and state enabled by VTL0 (AVX, for the Windows secure kernel) silently vanished across a VTL switch.
Propagate the validated value to every plane twin in __kvm_set_xcr(), covering both guest XSETBV and the KVM_SET_XCRS ioctl path. The CPUID dynamic-bits dirty marker lives in the shared common state, so the existing single set covers the twins. Signed-off-by: David Woodhouse <[email protected]> Assisted-by: LLM --- arch/x86/kvm/x86.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 491a0360c403..0f8a149ba0eb 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1361,6 +1361,28 @@ int __kvm_set_xcr(struct kvm_vcpu *vcpu, u32 index, u64 xcr) vcpu->arch.xcr0 = xcr0; + /* + * XCR0/XFEM is shared across VTLs (TLFS 15.4; the reference host + * banks no vector state): propagate the new value to every plane + * twin so the other VTLs observe it. This covers both guest + * XSETBV and the KVM_SET_XCRS ioctl path. The CPUID dirty marker + * below lives in the shared common state, so one set covers the + * twins too. + * + * Skip the fan-out until this vCPU is published in + * common->vcpus[]: the architectural reset of a twin still being + * created must not clobber a live sibling's XCR0 (the new twin + * inherits the shared value instead, in kvm_arch_vcpu_create()). + */ + if (vcpu->common && + vcpu->common->vcpus[vcpu->plane_level] == vcpu) { + struct kvm_vcpu *twin; + int i; + + vcpu_for_each_plane(vcpu->common, i, twin) + twin->arch.xcr0 = xcr0; + } + if ((xcr0 ^ old_xcr0) & XFEATURE_MASK_EXTEND) cpuid_set_dirty(vcpu); return 0; @@ -13549,6 +13571,14 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu) kvm_vcpu_after_set_cpuid(vcpu); kvm_set_tsc_khz(vcpu, vcpu->kvm->arch.default_tsc_khz); kvm_vcpu_reset(vcpu, false); + /* + * XCR0 is shared across planes. A twin created after its plane-0 + * sibling has run (Hyper-V VSM enables VTL1 at runtime) inherits + * the current shared value; the architectural reset value only + * stands when no sibling exists yet. + */ + if (vcpu->plane_level && vcpu->common->vcpus[0]) + vcpu->arch.xcr0 = vcpu->common->vcpus[0]->arch.xcr0; kvm_init_mmu(vcpu); vcpu_put(vcpu); return 0; -- 2.50.1

