]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
KVM: VMX: Don't modify guest XFD_ERR if CR0.TS=1
authorSean Christopherson <seanjc@google.com>
Tue, 1 Oct 2024 05:00:45 +0000 (22:00 -0700)
committerSean Christopherson <seanjc@google.com>
Tue, 25 Feb 2025 17:35:40 +0000 (09:35 -0800)
Don't update the guest's XFD_ERR MSR if CR0.TS is set; per the SDM,
XFD_ERR is not modified if CR0.TS=1.  Although it's not explicitly stated
in the SDM, conceptually it makes sense the CR0.TS check would be done
prior to the XFD_ERR check, e.g. CR0.TS=1 blocks all SIMD state, whereas
XFD blocks only XTILE state.

  Device-not-available exceptions that are not due to XFD - those
  resulting from setting CR0.TS to 1 - do not modify the IA32_XFD_ERR MSR.

Opportunistically update the comment to call out that XFD_ERR is updated
before the VM-Exit check occurs.  Nothing in the SDM explicitly calls out
this behavior, but logically it must be the behavior, otherwise reading
XFD_ERR in handle_nm_fault_irqoff() would return stale data, i.e. the
to-be-delivered XFD_ERR value would need to be saved in EXIT_QUALIFICATION,
a la DR6 for #DB and CR2 for #PF, so that software could capture the guest
value.

Fixes: ec5be88ab29f ("kvm: x86: Intercept #NM for saving IA32_XFD_ERR")
Signed-off-by: Xin Li (Intel) <xin@zytor.com>
Tested-by: Shan Kang <shan.kang@intel.com>
Link: https://lore.kernel.org/r/20241001050110.3643764-3-xin@zytor.com
Signed-off-by: Sean Christopherson <seanjc@google.com>
arch/x86/kvm/vmx/vmx.c

index f72835e85b6d5ade1fd47a1c03253d35e4daa149..24fcab183c1847dc65253adb3149f7f276e5cedb 100644 (file)
@@ -6995,16 +6995,16 @@ static void handle_nm_fault_irqoff(struct kvm_vcpu *vcpu)
         * MSR value is not clobbered by the host activity before the guest
         * has chance to consume it.
         *
-        * Do not blindly read xfd_err here, since this exception might
-        * be caused by L1 interception on a platform which doesn't
-        * support xfd at all.
+        * Update the guest's XFD_ERR if and only if XFD is enabled, as the #NM
+        * interception may have been caused by L1 interception.  Per the SDM,
+        * XFD_ERR is not modified if CR0.TS=1.
         *
-        * Do it conditionally upon guest_fpu::xfd. xfd_err matters
-        * only when xfd contains a non-zero value.
-        *
-        * Queuing exception is done in vmx_handle_exit. See comment there.
+        * Note, XFD_ERR is updated _before_ the #NM interception check, i.e.
+        * unlike CR2 and DR6, the value is not a payload that is attached to
+        * the #NM exception.
         */
-       if (vcpu->arch.guest_fpu.fpstate->xfd)
+       if (vcpu->arch.guest_fpu.fpstate->xfd &&
+           !kvm_is_cr0_bit_set(vcpu, X86_CR0_TS))
                rdmsrl(MSR_IA32_XFD_ERR, vcpu->arch.guest_fpu.xfd_err);
 }