linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Paolo Bonzini <pbonzini@redhat.com>
To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org
Cc: guang.zeng@intel.com, jing2.liu@intel.com, kevin.tian@intel.com,
	seanjc@google.com, tglx@linutronix.de, wei.w.wang@intel.com,
	yang.zhong@intel.com
Subject: [PATCH v6 12/21] kvm: x86: Intercept #NM for saving IA32_XFD_ERR
Date: Fri,  7 Jan 2022 13:55:03 -0500	[thread overview]
Message-ID: <20220107185512.25321-13-pbonzini@redhat.com> (raw)
In-Reply-To: <20220107185512.25321-1-pbonzini@redhat.com>

From: Jing Liu <jing2.liu@intel.com>

Guest IA32_XFD_ERR is generally modified in two places:

  - Set by CPU when #NM is triggered;
  - Cleared by guest in its #NM handler;

Intercept #NM for the first case when a nonzero value is written
to IA32_XFD. Nonzero indicates that the guest is willing to do
dynamic fpstate expansion for certain xfeatures, thus KVM needs to
manage and virtualize guest XFD_ERR properly. The vcpu exception
bitmap is updated in XFD write emulation according to guest_fpu::xfd.

Save the current XFD_ERR value to the guest_fpu container in the #NM
VM-exit handler. This must be done with interrupt disabled, otherwise
the unsaved MSR value may be clobbered by host activity.

The saving operation is conducted conditionally only when guest_fpu:xfd
includes a non-zero value. Doing so also avoids misread on a platform
which doesn't support XFD but #NM is triggered due to L1 interception.

Queueing #NM to the guest is postponed to handle_exception_nmi(). This
goes through the nested_vmx check so a virtual vmexit is queued instead
when #NM is triggered in L2 but L1 wants to intercept it.

Restore the host value (always ZERO outside of the host #NM
handler) before enabling interrupt.

Restore the guest value from the guest_fpu container right before
entering the guest (with interrupt disabled).

Suggested-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Jing Liu <jing2.liu@intel.com>
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Yang Zhong <yang.zhong@intel.com>
Message-Id: <20220105123532.12586-13-yang.zhong@intel.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 arch/x86/kvm/vmx/vmcs.h |  5 +++++
 arch/x86/kvm/vmx/vmx.c  | 48 +++++++++++++++++++++++++++++++++++++++++
 arch/x86/kvm/x86.c      |  6 ++++++
 3 files changed, 59 insertions(+)

diff --git a/arch/x86/kvm/vmx/vmcs.h b/arch/x86/kvm/vmx/vmcs.h
index 6e5de2e2b0da..e325c290a816 100644
--- a/arch/x86/kvm/vmx/vmcs.h
+++ b/arch/x86/kvm/vmx/vmcs.h
@@ -129,6 +129,11 @@ static inline bool is_machine_check(u32 intr_info)
 	return is_exception_n(intr_info, MC_VECTOR);
 }
 
+static inline bool is_nm_fault(u32 intr_info)
+{
+	return is_exception_n(intr_info, NM_VECTOR);
+}
+
 /* Undocumented: icebp/int1 */
 static inline bool is_icebp(u32 intr_info)
 {
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index 7b5abe25e1e5..84f6904cdb6e 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -36,6 +36,7 @@
 #include <asm/debugreg.h>
 #include <asm/desc.h>
 #include <asm/fpu/api.h>
+#include <asm/fpu/xstate.h>
 #include <asm/idtentry.h>
 #include <asm/io.h>
 #include <asm/irq_remapping.h>
@@ -761,6 +762,13 @@ void vmx_update_exception_bitmap(struct kvm_vcpu *vcpu)
 		vmcs_write32(PAGE_FAULT_ERROR_CODE_MATCH, match);
 	}
 
+	/*
+	 * Trap #NM if guest xfd contains a non-zero value so guest XFD_ERR
+	 * can be saved timely.
+	 */
+	if (vcpu->arch.guest_fpu.fpstate->xfd)
+		eb |= (1u << NM_VECTOR);
+
 	vmcs_write32(EXCEPTION_BITMAP, eb);
 }
 
@@ -1967,6 +1975,12 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
 	case MSR_KERNEL_GS_BASE:
 		vmx_write_guest_kernel_gs_base(vmx, data);
 		break;
+	case MSR_IA32_XFD:
+		ret = kvm_set_msr_common(vcpu, msr_info);
+		/* Update #NM interception according to guest xfd */
+		if (!ret)
+			vmx_update_exception_bitmap(vcpu);
+		break;
 #endif
 	case MSR_IA32_SYSENTER_CS:
 		if (is_guest_mode(vcpu))
@@ -4798,6 +4812,17 @@ static int handle_exception_nmi(struct kvm_vcpu *vcpu)
 	if (is_machine_check(intr_info) || is_nmi(intr_info))
 		return 1; /* handled by handle_exception_nmi_irqoff() */
 
+	/*
+	 * Queue the exception here instead of in handle_nm_fault_irqoff().
+	 * This ensures the nested_vmx check is not skipped so vmexit can
+	 * be reflected to L1 (when it intercepts #NM) before reaching this
+	 * point.
+	 */
+	if (is_nm_fault(intr_info)) {
+		kvm_queue_exception(vcpu, NM_VECTOR);
+		return 1;
+	}
+
 	if (is_invalid_opcode(intr_info))
 		return handle_ud(vcpu);
 
@@ -6399,6 +6424,26 @@ static void handle_interrupt_nmi_irqoff(struct kvm_vcpu *vcpu,
 	kvm_after_interrupt(vcpu);
 }
 
+static void handle_nm_fault_irqoff(struct kvm_vcpu *vcpu)
+{
+	/*
+	 * Save xfd_err to guest_fpu before interrupt is enabled, so the
+	 * 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.
+	 *
+	 * 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.
+	 */
+	if (vcpu->arch.guest_fpu.fpstate->xfd)
+		rdmsrl(MSR_IA32_XFD_ERR, vcpu->arch.guest_fpu.xfd_err);
+}
+
 static void handle_exception_nmi_irqoff(struct vcpu_vmx *vmx)
 {
 	const unsigned long nmi_entry = (unsigned long)asm_exc_nmi_noist;
@@ -6407,6 +6452,9 @@ static void handle_exception_nmi_irqoff(struct vcpu_vmx *vmx)
 	/* if exit due to PF check for async PF */
 	if (is_page_fault(intr_info))
 		vmx->vcpu.arch.apf.host_apf_flags = kvm_read_and_reset_apf_flags();
+	/* if exit due to NM, handle before interrupts are enabled */
+	else if (is_nm_fault(intr_info))
+		handle_nm_fault_irqoff(&vmx->vcpu);
 	/* Handle machine checks before interrupts are enabled */
 	else if (is_machine_check(intr_info))
 		kvm_machine_check();
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index b18d2838606f..bb9534590a3a 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -9952,6 +9952,9 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
 	if (test_thread_flag(TIF_NEED_FPU_LOAD))
 		switch_fpu_return();
 
+	if (vcpu->arch.guest_fpu.xfd_err)
+		wrmsrl(MSR_IA32_XFD_ERR, vcpu->arch.guest_fpu.xfd_err);
+
 	if (unlikely(vcpu->arch.switch_db_regs)) {
 		set_debugreg(0, 7);
 		set_debugreg(vcpu->arch.eff_db[0], 0);
@@ -10015,6 +10018,9 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
 
 	static_call(kvm_x86_handle_exit_irqoff)(vcpu);
 
+	if (vcpu->arch.guest_fpu.xfd_err)
+		wrmsrl(MSR_IA32_XFD_ERR, 0);
+
 	/*
 	 * Consume any pending interrupts, including the possible source of
 	 * VM-Exit on SVM and any ticks that occur between VM-Exit and now.
-- 
2.31.1



  parent reply	other threads:[~2022-01-07 18:56 UTC|newest]

Thread overview: 35+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-01-07 18:54 [PATCH v6 00/21] AMX support for KVM Paolo Bonzini
2022-01-07 18:54 ` [PATCH v6 01/21] x86/fpu: Extend fpu_xstate_prctl() with guest permissions Paolo Bonzini
2022-01-07 18:54 ` [PATCH v6 02/21] x86/fpu: Prepare guest FPU for dynamically enabled FPU features Paolo Bonzini
2022-01-07 18:54 ` [PATCH v6 03/21] kvm: x86: Fix xstate_required_size() to follow XSTATE alignment rule Paolo Bonzini
2022-01-07 18:54 ` [PATCH v6 04/21] kvm: x86: Exclude unpermitted xfeatures at KVM_GET_SUPPORTED_CPUID Paolo Bonzini
2022-01-23  6:22   ` Like Xu
2022-01-24  7:18     ` Tian, Kevin
2022-01-07 18:54 ` [PATCH v6 05/21] x86/fpu: Make XFD initialization in __fpstate_reset() a function argument Paolo Bonzini
2022-01-07 19:43   ` Borislav Petkov
2022-01-10  5:15     ` Tian, Kevin
2022-01-10  8:52       ` Borislav Petkov
2022-01-10 14:18         ` Paolo Bonzini
2022-01-10 15:25           ` Borislav Petkov
2022-01-10 15:55             ` Paolo Bonzini
2022-01-10 18:18               ` Borislav Petkov
2022-01-11  1:45                 ` Tian, Kevin
2022-01-07 18:54 ` [PATCH v6 06/21] x86/fpu: Add guest support to xfd_enable_feature() Paolo Bonzini
2022-01-07 18:54 ` [PATCH v6 07/21] x86/fpu: Provide fpu_enable_guest_xfd_features() for KVM Paolo Bonzini
2022-01-10  5:25   ` Tian, Kevin
2022-01-07 18:54 ` [PATCH v6 08/21] kvm: x86: Enable dynamic xfeatures at KVM_SET_CPUID2 Paolo Bonzini
2022-01-07 18:55 ` [PATCH v6 09/21] x86/fpu: Provide fpu_update_guest_xfd() for IA32_XFD emulation Paolo Bonzini
2022-01-07 18:55 ` [PATCH v6 10/21] kvm: x86: Add emulation for IA32_XFD Paolo Bonzini
2022-01-07 18:55 ` [PATCH v6 11/21] x86/fpu: Prepare xfd_err in struct fpu_guest Paolo Bonzini
2022-01-07 18:55 ` Paolo Bonzini [this message]
2022-01-07 18:55 ` [PATCH v6 13/21] kvm: x86: Emulate IA32_XFD_ERR for guest Paolo Bonzini
2022-01-07 18:55 ` [PATCH v6 14/21] kvm: x86: Disable RDMSR interception of IA32_XFD_ERR Paolo Bonzini
2022-01-07 18:55 ` [PATCH v6 15/21] kvm: x86: Add XCR0 support for Intel AMX Paolo Bonzini
2022-01-07 18:55 ` [PATCH v6 16/21] kvm: x86: Add CPUID " Paolo Bonzini
2022-01-07 18:55 ` [PATCH v6 17/21] x86/fpu: Add uabi_size to guest_fpu Paolo Bonzini
2022-01-07 18:55 ` [PATCH v6 18/21] kvm: x86: Add support for getting/setting expanded xstate buffer Paolo Bonzini
2022-01-07 18:55 ` [PATCH v6 19/21] kvm: selftests: Add support for KVM_CAP_XSAVE2 Paolo Bonzini
2022-01-17 16:51   ` Janis Schoetterl-Glausch
2022-01-18  2:06     ` Wang, Wei W
2022-01-07 18:55 ` [PATCH v6 20/21] x86/fpu: Provide fpu_sync_guest_vmexit_xfd_state() Paolo Bonzini
2022-01-07 18:55 ` [PATCH v6 21/21] kvm: x86: Disable interception for IA32_XFD on demand Paolo Bonzini

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=20220107185512.25321-13-pbonzini@redhat.com \
    --to=pbonzini@redhat.com \
    --cc=guang.zeng@intel.com \
    --cc=jing2.liu@intel.com \
    --cc=kevin.tian@intel.com \
    --cc=kvm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=seanjc@google.com \
    --cc=tglx@linutronix.de \
    --cc=wei.w.wang@intel.com \
    --cc=yang.zhong@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;
as well as URLs for NNTP newsgroup(s).