From: Maxim Levitsky <mlevitsk@redhat.com>
To: kvm@vger.kernel.org
Cc: Sandipan Das <sandipan.das@amd.com>,
Paolo Bonzini <pbonzini@redhat.com>,
Jim Mattson <jmattson@google.com>,
Peter Zijlstra <peterz@infradead.org>,
Dave Hansen <dave.hansen@linux.intel.com>,
Borislav Petkov <bp@alien8.de>,
Pawan Gupta <pawan.kumar.gupta@linux.intel.com>,
Thomas Gleixner <tglx@linutronix.de>,
Ingo Molnar <mingo@redhat.com>,
Josh Poimboeuf <jpoimboe@kernel.org>,
Daniel Sneddon <daniel.sneddon@linux.intel.com>,
Jiaxi Chen <jiaxi.chen@linux.intel.com>,
Babu Moger <babu.moger@amd.com>,
linux-kernel@vger.kernel.org, Jing Liu <jing2.liu@intel.com>,
Wyes Karny <wyes.karny@amd.com>,
x86@kernel.org, "H. Peter Anvin" <hpa@zytor.com>,
Sean Christopherson <seanjc@google.com>,
Maxim Levitsky <mlevitsk@redhat.com>
Subject: [PATCH v2 07/11] KVM: x86: add a delayed hardware NMI injection interface
Date: Tue, 29 Nov 2022 21:37:13 +0200 [thread overview]
Message-ID: <20221129193717.513824-8-mlevitsk@redhat.com> (raw)
In-Reply-To: <20221129193717.513824-1-mlevitsk@redhat.com>
This patch adds two new vendor callbacks:
- kvm_x86_get_hw_nmi_pending()
- kvm_x86_set_hw_nmi_pending()
Using those callbacks the KVM can take advantage of the
hardware's accelerated delayed NMI delivery (currently vNMI on SVM).
Once NMI is set to pending via this interface, it is assumed that
the hardware will deliver the NMI on its own to the guest once
all the x86 conditions for the NMI delivery are met.
Note that the 'kvm_x86_set_hw_nmi_pending()' callback is allowed
to fail, in which case a normal NMI injection will be attempted
when NMI can be delivered (possibly by using a NMI window).
With vNMI that can happen either if vNMI is already pending or
if a nested guest is running.
When the vNMI injection fails due to the 'vNMI is already pending'
condition, the new NMI will be dropped unless the new NMI can be
injected immediately, so no NMI window will be requested.
Signed-off-by: Maxim Levitsky <mlevitsk@redhat.com>
---
arch/x86/include/asm/kvm-x86-ops.h | 2 ++
arch/x86/include/asm/kvm_host.h | 15 ++++++++++++-
arch/x86/kvm/x86.c | 36 ++++++++++++++++++++++++++----
3 files changed, 48 insertions(+), 5 deletions(-)
diff --git a/arch/x86/include/asm/kvm-x86-ops.h b/arch/x86/include/asm/kvm-x86-ops.h
index abccd51dcfca1b..9e2db6cf7cc041 100644
--- a/arch/x86/include/asm/kvm-x86-ops.h
+++ b/arch/x86/include/asm/kvm-x86-ops.h
@@ -67,6 +67,8 @@ KVM_X86_OP(get_interrupt_shadow)
KVM_X86_OP(patch_hypercall)
KVM_X86_OP(inject_irq)
KVM_X86_OP(inject_nmi)
+KVM_X86_OP_OPTIONAL_RET0(get_hw_nmi_pending)
+KVM_X86_OP_OPTIONAL_RET0(set_hw_nmi_pending)
KVM_X86_OP(inject_exception)
KVM_X86_OP(cancel_injection)
KVM_X86_OP(interrupt_allowed)
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 684a5519812fb2..46993ce61c92db 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -871,8 +871,13 @@ struct kvm_vcpu_arch {
u64 tsc_scaling_ratio; /* current scaling ratio */
atomic_t nmi_queued; /* unprocessed asynchronous NMIs */
- unsigned nmi_pending; /* NMI queued after currently running handler */
+
+ unsigned int nmi_pending; /*
+ * NMI queued after currently running handler
+ * (not including a hardware pending NMI (e.g vNMI))
+ */
bool nmi_injected; /* Trying to inject an NMI this entry */
+
bool smi_pending; /* SMI queued after currently running handler */
u8 handling_intr_from_guest;
@@ -1602,6 +1607,13 @@ struct kvm_x86_ops {
int (*nmi_allowed)(struct kvm_vcpu *vcpu, bool for_injection);
bool (*get_nmi_mask)(struct kvm_vcpu *vcpu);
void (*set_nmi_mask)(struct kvm_vcpu *vcpu, bool masked);
+
+ /* returns true, if a NMI is pending injection on hardware level (e.g vNMI) */
+ bool (*get_hw_nmi_pending)(struct kvm_vcpu *vcpu);
+
+ /* attempts make a NMI pending via hardware interface (e.g vNMI) */
+ bool (*set_hw_nmi_pending)(struct kvm_vcpu *vcpu);
+
void (*enable_nmi_window)(struct kvm_vcpu *vcpu);
void (*enable_irq_window)(struct kvm_vcpu *vcpu);
void (*update_cr8_intercept)(struct kvm_vcpu *vcpu, int tpr, int irr);
@@ -1964,6 +1976,7 @@ int kvm_pic_set_irq(struct kvm_pic *pic, int irq, int irq_source_id, int level);
void kvm_pic_clear_all(struct kvm_pic *pic, int irq_source_id);
void kvm_inject_nmi(struct kvm_vcpu *vcpu);
+int kvm_get_total_nmi_pending(struct kvm_vcpu *vcpu);
void kvm_update_dr7(struct kvm_vcpu *vcpu);
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 85d2a12c214dda..3c30e3f1106f79 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -5103,7 +5103,7 @@ static void kvm_vcpu_ioctl_x86_get_vcpu_events(struct kvm_vcpu *vcpu,
events->interrupt.shadow = static_call(kvm_x86_get_interrupt_shadow)(vcpu);
events->nmi.injected = vcpu->arch.nmi_injected;
- events->nmi.pending = vcpu->arch.nmi_pending != 0;
+ events->nmi.pending = kvm_get_total_nmi_pending(vcpu) != 0;
events->nmi.masked = static_call(kvm_x86_get_nmi_mask)(vcpu);
/* events->sipi_vector is never valid when reporting to user space */
@@ -5191,9 +5191,12 @@ static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu,
vcpu->arch.nmi_injected = events->nmi.injected;
if (events->flags & KVM_VCPUEVENT_VALID_NMI_PENDING)
- vcpu->arch.nmi_pending = events->nmi.pending;
+ atomic_add(events->nmi.pending, &vcpu->arch.nmi_queued);
+
static_call(kvm_x86_set_nmi_mask)(vcpu, events->nmi.masked);
+ process_nmi(vcpu);
+
if (events->flags & KVM_VCPUEVENT_VALID_SIPI_VECTOR &&
lapic_in_kernel(vcpu))
vcpu->arch.apic->sipi_vector = events->sipi_vector;
@@ -10008,6 +10011,10 @@ static int kvm_check_and_inject_events(struct kvm_vcpu *vcpu,
static void process_nmi(struct kvm_vcpu *vcpu)
{
unsigned limit = 2;
+ int nmi_to_queue = atomic_xchg(&vcpu->arch.nmi_queued, 0);
+
+ if (!nmi_to_queue)
+ return;
/*
* x86 is limited to one NMI running, and one NMI pending after it.
@@ -10015,13 +10022,34 @@ static void process_nmi(struct kvm_vcpu *vcpu)
* Otherwise, allow two (and we'll inject the first one immediately).
*/
if (static_call(kvm_x86_get_nmi_mask)(vcpu) || vcpu->arch.nmi_injected)
- limit = 1;
+ limit--;
+
+ /* Also if there is already a NMI hardware queued to be injected,
+ * decrease the limit again
+ */
+ if (static_call(kvm_x86_get_hw_nmi_pending)(vcpu))
+ limit--;
- vcpu->arch.nmi_pending += atomic_xchg(&vcpu->arch.nmi_queued, 0);
+ if (limit <= 0)
+ return;
+
+ /* Attempt to use hardware NMI queueing */
+ if (static_call(kvm_x86_set_hw_nmi_pending)(vcpu)) {
+ limit--;
+ nmi_to_queue--;
+ }
+
+ vcpu->arch.nmi_pending += nmi_to_queue;
vcpu->arch.nmi_pending = min(vcpu->arch.nmi_pending, limit);
kvm_make_request(KVM_REQ_EVENT, vcpu);
}
+/* Return total number of NMIs pending injection to the VM */
+int kvm_get_total_nmi_pending(struct kvm_vcpu *vcpu)
+{
+ return vcpu->arch.nmi_pending + static_call(kvm_x86_get_hw_nmi_pending)(vcpu);
+}
+
void kvm_make_scan_ioapic_request_mask(struct kvm *kvm,
unsigned long *vcpu_bitmap)
{
--
2.26.3
next prev parent reply other threads:[~2022-11-29 19:41 UTC|newest]
Thread overview: 66+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-11-29 19:37 [PATCH v2 00/11] SVM: vNMI (with my fixes) Maxim Levitsky
2022-11-29 19:37 ` [PATCH v2 01/11] KVM: nSVM: don't sync back tlb_ctl on nested VM exit Maxim Levitsky
2022-12-05 14:05 ` Santosh Shukla
2022-12-06 12:13 ` Maxim Levitsky
2022-11-29 19:37 ` [PATCH v2 02/11] KVM: nSVM: clean up the copying of V_INTR bits from vmcb02 to vmcb12 Maxim Levitsky
2023-01-28 0:37 ` Sean Christopherson
2023-01-31 1:44 ` Sean Christopherson
2023-02-24 14:38 ` Maxim Levitsky
2023-02-24 16:48 ` Sean Christopherson
2022-11-29 19:37 ` [PATCH v2 03/11] KVM: nSVM: explicitly raise KVM_REQ_EVENT on nested VM exit if L1 doesn't intercept interrupts Maxim Levitsky
2023-01-28 0:56 ` Sean Christopherson
2023-01-30 18:41 ` Sean Christopherson
2022-11-29 19:37 ` [PATCH v2 04/11] KVM: SVM: drop the SVM specific H_FLAGS Maxim Levitsky
2022-12-05 15:31 ` Santosh Shukla
2023-01-28 0:56 ` Sean Christopherson
2022-11-29 19:37 ` [PATCH v2 05/11] KVM: x86: emulator: stop using raw host flags Maxim Levitsky
2023-01-28 0:58 ` Sean Christopherson
2023-02-24 14:38 ` Maxim Levitsky
2022-11-29 19:37 ` [PATCH v2 06/11] KVM: SVM: add wrappers to enable/disable IRET interception Maxim Levitsky
2022-12-05 15:41 ` Santosh Shukla
2022-12-06 12:14 ` Maxim Levitsky
2022-12-08 12:09 ` Santosh Shukla
2022-12-08 13:44 ` Maxim Levitsky
2023-01-31 21:07 ` Sean Christopherson
2023-02-13 14:50 ` Santosh Shukla
2022-11-29 19:37 ` Maxim Levitsky [this message]
2023-01-28 1:09 ` [PATCH v2 07/11] KVM: x86: add a delayed hardware NMI injection interface Sean Christopherson
2023-01-31 21:12 ` Sean Christopherson
2023-02-08 9:35 ` Santosh Shukla
2023-02-08 9:32 ` Santosh Shukla
2023-02-24 14:39 ` Maxim Levitsky
2023-01-31 22:28 ` Sean Christopherson
2023-02-01 0:06 ` Sean Christopherson
2023-02-08 9:51 ` Santosh Shukla
2023-02-08 16:09 ` Sean Christopherson
2023-02-08 9:43 ` Santosh Shukla
2023-02-08 16:06 ` Sean Christopherson
2023-02-14 10:22 ` Santosh Shukla
2023-02-15 22:43 ` Sean Christopherson
2023-02-16 0:22 ` Sean Christopherson
2023-02-17 7:56 ` Santosh Shukla
2022-11-29 19:37 ` [PATCH v2 08/11] x86/cpu: Add CPUID feature bit for VNMI Maxim Levitsky
2022-11-29 19:37 ` [PATCH v2 09/11] KVM: SVM: Add VNMI bit definition Maxim Levitsky
2023-01-31 22:42 ` Sean Christopherson
2023-02-02 9:42 ` Santosh Shukla
2022-11-29 19:37 ` [PATCH v2 10/11] KVM: SVM: implement support for vNMI Maxim Levitsky
2022-12-04 17:18 ` Maxim Levitsky
2022-12-05 17:07 ` Santosh Shukla
2023-01-28 1:10 ` Sean Christopherson
2023-02-10 12:02 ` Santosh Shukla
2023-02-01 0:22 ` Sean Christopherson
2023-02-01 0:39 ` Sean Christopherson
2023-02-10 12:24 ` Santosh Shukla
2023-02-10 16:44 ` Sean Christopherson
2022-11-29 19:37 ` [PATCH v2 11/11] KVM: nSVM: implement support for nested VNMI Maxim Levitsky
2022-12-05 17:14 ` Santosh Shukla
2022-12-06 12:19 ` Maxim Levitsky
2022-12-08 12:11 ` Santosh Shukla
2023-02-01 0:44 ` Sean Christopherson
2022-12-06 9:58 ` [PATCH v2 00/11] SVM: vNMI (with my fixes) Santosh Shukla
2023-02-01 0:24 ` Sean Christopherson
2022-12-20 10:27 ` Maxim Levitsky
2022-12-21 18:44 ` Sean Christopherson
2023-01-15 9:05 ` Maxim Levitsky
2023-01-28 1:13 ` Sean Christopherson
2023-02-01 19:13 ` Sean Christopherson
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=20221129193717.513824-8-mlevitsk@redhat.com \
--to=mlevitsk@redhat.com \
--cc=babu.moger@amd.com \
--cc=bp@alien8.de \
--cc=daniel.sneddon@linux.intel.com \
--cc=dave.hansen@linux.intel.com \
--cc=hpa@zytor.com \
--cc=jiaxi.chen@linux.intel.com \
--cc=jing2.liu@intel.com \
--cc=jmattson@google.com \
--cc=jpoimboe@kernel.org \
--cc=kvm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@redhat.com \
--cc=pawan.kumar.gupta@linux.intel.com \
--cc=pbonzini@redhat.com \
--cc=peterz@infradead.org \
--cc=sandipan.das@amd.com \
--cc=seanjc@google.com \
--cc=tglx@linutronix.de \
--cc=wyes.karny@amd.com \
--cc=x86@kernel.org \
/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
all inboxes | Powered by JetHome®