mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Neeraj Upadhyay <Neeraj.Upadhyay@amd.com>
To: <seanjc@google.com>, <pbonzini@redhat.com>, <kvm@vger.kernel.org>
Cc: <linux-kernel@vger.kernel.org>, <bp@alien8.de>,
	<tglx@linutronix.de>, <mingo@redhat.com>,
	<dave.hansen@linux.intel.com>, <Thomas.Lendacky@amd.com>,
	<nikunj@amd.com>, <Santosh.Shukla@amd.com>,
	<Vasant.Hegde@amd.com>, <Suravee.Suthikulpanit@amd.com>,
	<David.Kaplan@amd.com>, <x86@kernel.org>, <hpa@zytor.com>,
	<peterz@infradead.org>, <huibo.wang@amd.com>,
	<naveen.rao@amd.com>, <binbin.wu@linux.intel.com>,
	<isaku.yamahata@intel.com>
Subject: [RFC PATCH 08/19] KVM: SVM/SEV/X86: Secure AVIC: Add support to inject interrupts
Date: Fri, 28 Feb 2025 14:21:04 +0530	[thread overview]
Message-ID: <20250228085115.105648-9-Neeraj.Upadhyay@amd.com> (raw)
In-Reply-To: <20250228085115.105648-1-Neeraj.Upadhyay@amd.com>

Add support to inject interrupts from emulated devices/para-virtualized
devices for Secure AVIC guests. Secure AVIC requires RequestedIRR and
UpdateIRR VMCB fields to be set before VMRUN for interrupt injection.

Secure AVIC allows multiple interrupts to be injected at the same time. So
on interrupt injection, the entire contents of APIC_IRR in host APIC
backing page are copied to RequestedIRR. As guest PPR state is not visible
in KVM, all pending interrupts in host APIC_IRR are considered as
injectable. Secure AVIC HW handles re-injection itself so no explicit
handling by KVM is required.

Secure AVIC does not require an IRQ window as hardware manages interrupt
delivery to the guest and can detect if the guest is in a state to accept
interrupts. So, short-circuit interrupt_allowed() and enable_irq_window()
ops for Secure AVIC.

Co-developed-by: Kishon Vijay Abraham I <kvijayab@amd.com>
Signed-off-by: Kishon Vijay Abraham I <kvijayab@amd.com>
Signed-off-by: Neeraj Upadhyay <Neeraj.Upadhyay@amd.com>
---
 arch/x86/include/asm/svm.h |  8 ++++++--
 arch/x86/kvm/irq.c         |  3 +++
 arch/x86/kvm/lapic.c       | 13 +++++++++----
 arch/x86/kvm/svm/sev.c     | 39 ++++++++++++++++++++++++++++++++++++++
 arch/x86/kvm/svm/svm.c     | 13 +++++++++++++
 arch/x86/kvm/svm/svm.h     |  5 ++++-
 arch/x86/kvm/x86.c         | 12 +++++++++++-
 7 files changed, 85 insertions(+), 8 deletions(-)

diff --git a/arch/x86/include/asm/svm.h b/arch/x86/include/asm/svm.h
index f81b417fe836..59253e3b28f3 100644
--- a/arch/x86/include/asm/svm.h
+++ b/arch/x86/include/asm/svm.h
@@ -159,9 +159,13 @@ struct __attribute__ ((__packed__)) vmcb_control_area {
 	u64 avic_physical_id;	/* Offset 0xf8 */
 	u8 reserved_7[8];
 	u64 vmsa_pa;		/* Used for an SEV-ES guest */
-	u8 reserved_8[40];
+	u8 reserved_8[36];
+	u8 update_irr;			/* Offset 0x134 */
+	u8 reserved_9[3];
 	u64 allowed_sev_features;	/* Offset 0x138 */
-	u8 reserved_9[672];
+	u8 reserved_10[16];
+	u32 requested_irr[8];		/* Offset 0x150 */
+	u8 reserved_11[624];
 	/*
 	 * Offset 0x3e0, 32 bytes reserved
 	 * for use by hypervisor/software.
diff --git a/arch/x86/kvm/irq.c b/arch/x86/kvm/irq.c
index f0644d0bbe11..fbfd897ea412 100644
--- a/arch/x86/kvm/irq.c
+++ b/arch/x86/kvm/irq.c
@@ -47,6 +47,9 @@ static int pending_userspace_extint(struct kvm_vcpu *v)
  */
 int kvm_cpu_has_extint(struct kvm_vcpu *v)
 {
+	if (v->arch.apic->guest_apic_protected)
+		return 0;
+
 	/*
 	 * FIXME: interrupt.injected represents an interrupt whose
 	 * side-effects have already been applied (e.g. bit from IRR
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 65f69537c105..7b2ee5263644 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -2975,11 +2975,16 @@ int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu)
 	if (!kvm_apic_present(vcpu))
 		return -1;
 
-	if (apic->guest_apic_protected)
+	switch (apic->guest_apic_protected) {
+	case APIC_STATE_PROTECTED_POSTED_INTR:
 		return -1;
-
-	__apic_update_ppr(apic, &ppr);
-	return apic_has_interrupt_for_ppr(apic, ppr);
+	case APIC_STATE_PROTECTED_INJECTED_INTR:
+		return apic_search_irr(apic);
+	case APIC_STATE_UNPROTECTED:
+	default:
+		__apic_update_ppr(apic, &ppr);
+		return apic_has_interrupt_for_ppr(apic, ppr);
+	}
 }
 EXPORT_SYMBOL_GPL(kvm_apic_has_interrupt);
 
diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
index 6313679a65b8..080b71ade88d 100644
--- a/arch/x86/kvm/svm/sev.c
+++ b/arch/x86/kvm/svm/sev.c
@@ -34,6 +34,7 @@
 #include "svm_ops.h"
 #include "cpuid.h"
 #include "trace.h"
+#include "lapic.h"
 
 #define GHCB_VERSION_MAX	2ULL
 #define GHCB_VERSION_DEFAULT	2ULL
@@ -4986,3 +4987,41 @@ int sev_private_max_mapping_level(struct kvm *kvm, kvm_pfn_t pfn)
 
 	return level;
 }
+
+void sev_savic_set_requested_irr(struct vcpu_svm *svm, bool reinjected)
+{
+	struct kvm_lapic *apic;
+	bool has_interrupts;
+	int vec, vec_pos;
+	u32 val;
+	int i;
+
+	/* Secure AVIC HW takes care of re-injection */
+	if (reinjected)
+		return;
+
+	apic = svm->vcpu.arch.apic;
+	has_interrupts = false;
+
+	for (i = 0; i < ARRAY_SIZE(svm->vmcb->control.requested_irr); i++) {
+		val = __kvm_lapic_get_reg(apic->regs, APIC_IRR + i * 0x10);
+		if (!val)
+			continue;
+		has_interrupts = true;
+		svm->vmcb->control.requested_irr[i] |= val;
+		do {
+			vec_pos = __ffs(val);
+			vec = (i << 5) + vec_pos;
+			kvm_lapic_clear_vector(vec, apic->regs + APIC_IRR);
+			val = val & ~BIT(vec_pos);
+		} while (val);
+	}
+
+	if (has_interrupts)
+		svm->vmcb->control.update_irr |= BIT(0);
+}
+
+bool sev_savic_has_pending_interrupt(struct kvm_vcpu *vcpu)
+{
+	return kvm_apic_has_interrupt(vcpu) != -1;
+}
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index d00ae58c0b0a..7cfd6e916c74 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -50,6 +50,8 @@
 #include "svm.h"
 #include "svm_ops.h"
 
+#include "lapic.h"
+
 #include "kvm_onhyperv.h"
 #include "svm_onhyperv.h"
 
@@ -3679,6 +3681,9 @@ static void svm_inject_irq(struct kvm_vcpu *vcpu, bool reinjected)
 	struct vcpu_svm *svm = to_svm(vcpu);
 	u32 type;
 
+	if (sev_savic_active(vcpu->kvm))
+		return sev_savic_set_requested_irr(svm, reinjected);
+
 	if (vcpu->arch.interrupt.soft) {
 		if (svm_update_soft_interrupt_rip(vcpu))
 			return;
@@ -3860,6 +3865,9 @@ static int svm_interrupt_allowed(struct kvm_vcpu *vcpu, bool for_injection)
 {
 	struct vcpu_svm *svm = to_svm(vcpu);
 
+	if (sev_savic_active(vcpu->kvm))
+		return 1;
+
 	if (svm->nested.nested_run_pending)
 		return -EBUSY;
 
@@ -3880,6 +3888,9 @@ static void svm_enable_irq_window(struct kvm_vcpu *vcpu)
 {
 	struct vcpu_svm *svm = to_svm(vcpu);
 
+	if (sev_savic_active(vcpu->kvm))
+		return;
+
 	/*
 	 * In case GIF=0 we can't rely on the CPU to tell us when GIF becomes
 	 * 1, because that's a separate STGI/VMRUN intercept.  The next time we
@@ -5092,6 +5103,8 @@ static struct kvm_x86_ops svm_x86_ops __initdata = {
 	.apicv_post_state_restore = avic_apicv_post_state_restore,
 	.required_apicv_inhibits = AVIC_REQUIRED_APICV_INHIBITS,
 
+	.protected_apic_has_interrupt = sev_savic_has_pending_interrupt,
+
 	.get_exit_info = svm_get_exit_info,
 	.get_entry_info = svm_get_entry_info,
 
diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h
index e855f101e60f..f70c161ad352 100644
--- a/arch/x86/kvm/svm/svm.h
+++ b/arch/x86/kvm/svm/svm.h
@@ -760,6 +760,8 @@ static inline bool sev_savic_active(struct kvm *kvm)
 {
 	return to_kvm_sev_info(kvm)->vmsa_features & SVM_SEV_FEAT_SECURE_AVIC;
 }
+void sev_savic_set_requested_irr(struct vcpu_svm *svm, bool reinjected);
+bool sev_savic_has_pending_interrupt(struct kvm_vcpu *vcpu);
 #else
 static inline struct page *snp_safe_alloc_page_node(int node, gfp_t gfp)
 {
@@ -791,7 +793,8 @@ static inline int sev_private_max_mapping_level(struct kvm *kvm, kvm_pfn_t pfn)
 	return 0;
 }
 static inline bool sev_savic_active(struct kvm *kvm) { return false; }
-
+static inline void sev_savic_set_requested_irr(struct vcpu_svm *svm, bool reinjected) {}
+static inline bool sev_savic_has_pending_interrupt(struct kvm_vcpu *vcpu) { return false; }
 #endif
 
 /* vmenter.S */
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 8e77e61d4fbd..a9bd774baa4e 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -10426,7 +10426,17 @@ static int kvm_check_and_inject_events(struct kvm_vcpu *vcpu,
 		if (r < 0)
 			goto out;
 		if (r) {
-			int irq = kvm_cpu_get_interrupt(vcpu);
+			int irq;
+
+			/*
+			 * Do not ack the interrupt here for APIC_STATE_PROTECTED_INJECTED_INTR.
+			 * ->inject_irq reads the APIC_IRR state and clears it.
+			 */
+			if (vcpu->arch.apic->guest_apic_protected ==
+					APIC_STATE_PROTECTED_INJECTED_INTR)
+				irq = kvm_apic_has_interrupt(vcpu);
+			else
+				irq = kvm_cpu_get_interrupt(vcpu);
 
 			if (!WARN_ON_ONCE(irq == -1)) {
 				kvm_queue_interrupt(vcpu, irq, false);
-- 
2.34.1


  parent reply	other threads:[~2025-02-28  9:07 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-02-28  8:50 [RFC PATCH 00/19] AMD: Add Secure AVIC KVM Support Neeraj Upadhyay
2025-02-28  8:50 ` [RFC PATCH 01/19] KVM: TDX: Add support for find pending IRQ in a protected local APIC Neeraj Upadhyay
2025-02-28  8:50 ` [RFC PATCH 02/19] KVM: x86: Assume timer IRQ was injected if APIC state is protected Neeraj Upadhyay
2025-02-28  8:50 ` [RFC PATCH 03/19] KVM: x86: Convert guest_apic_protected bool to an enum type Neeraj Upadhyay
2025-02-28  8:51 ` [RFC PATCH 04/19] x86/cpufeatures: Add Secure AVIC CPU Feature Neeraj Upadhyay
2025-02-28  8:51 ` [RFC PATCH 05/19] KVM: SVM: Add support for Secure AVIC capability in KVM Neeraj Upadhyay
2025-02-28  8:51 ` [RFC PATCH 06/19] KVM: SVM: Initialize apic protected state for SAVIC guests Neeraj Upadhyay
2025-02-28  8:51 ` [RFC PATCH 07/19] KVM: SEV: Do not intercept SECURE_AVIC_CONTROL MSR Neeraj Upadhyay
2025-02-28  8:51 ` Neeraj Upadhyay [this message]
2025-02-28  8:51 ` [RFC PATCH 09/19] KVM: SVM/SEV/X86: Secure AVIC: Add hypervisor side IPI Delivery Support Neeraj Upadhyay
2025-02-28  8:51 ` [RFC PATCH 10/19] KVM: SVM: Secure AVIC: Do not inject "Exceptions" for Secure AVIC Neeraj Upadhyay
2025-02-28  8:51 ` [RFC PATCH 11/19] KVM: SVM/SEV: Do not intercept exceptions for Secure AVIC guest Neeraj Upadhyay
2025-02-28  8:51 ` [RFC PATCH 12/19] KVM: SVM/SEV: Secure AVIC: Set VGIF in VMSA area Neeraj Upadhyay
2025-02-28  8:51 ` [RFC PATCH 13/19] KVM: SVM/SEV: Secure AVIC: Enable NMI support Neeraj Upadhyay
2025-02-28  8:51 ` [RFC PATCH 14/19] KVM: SVM/SEV: Add SVM_VMGEXIT_SECURE_AVIC GHCB protocol event handling Neeraj Upadhyay
2025-02-28  8:51 ` [RFC PATCH 15/19] KVM: x86: Secure AVIC: Indicate APIC is enabled by guest SW _always_ Neeraj Upadhyay
2025-02-28  8:51 ` [RFC PATCH 16/19] KVM: x86: Secure AVIC: Add IOAPIC EOI support for level interrupts Neeraj Upadhyay
2025-02-28  8:51 ` [RFC PATCH 17/19] KVM: x86/ioapic: Disable RTC_GSI EOI tracking for protected APIC Neeraj Upadhyay
2025-02-28  8:51 ` [RFC PATCH 18/19] X86: SVM: Check injected vectors before waiting for timer expiry Neeraj Upadhyay
2025-02-28  8:51 ` [RFC PATCH 19/19] KVM: SVM/SEV: Allow creating VMs with Secure AVIC enabled Neeraj Upadhyay

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=20250228085115.105648-9-Neeraj.Upadhyay@amd.com \
    --to=neeraj.upadhyay@amd.com \
    --cc=David.Kaplan@amd.com \
    --cc=Santosh.Shukla@amd.com \
    --cc=Suravee.Suthikulpanit@amd.com \
    --cc=Thomas.Lendacky@amd.com \
    --cc=Vasant.Hegde@amd.com \
    --cc=binbin.wu@linux.intel.com \
    --cc=bp@alien8.de \
    --cc=dave.hansen@linux.intel.com \
    --cc=hpa@zytor.com \
    --cc=huibo.wang@amd.com \
    --cc=isaku.yamahata@intel.com \
    --cc=kvm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@redhat.com \
    --cc=naveen.rao@amd.com \
    --cc=nikunj@amd.com \
    --cc=pbonzini@redhat.com \
    --cc=peterz@infradead.org \
    --cc=seanjc@google.com \
    --cc=tglx@linutronix.de \
    --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®