public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Neeraj Upadhyay <Neeraj.Upadhyay@amd.com>
To: <kvm@vger.kernel.org>, <seanjc@google.com>, <pbonzini@redhat.com>
Cc: <linux-kernel@vger.kernel.org>, <Thomas.Lendacky@amd.com>,
	<nikunj@amd.com>, <Santosh.Shukla@amd.com>,
	<Vasant.Hegde@amd.com>, <Suravee.Suthikulpanit@amd.com>,
	<bp@alien8.de>, <David.Kaplan@amd.com>, <huibo.wang@amd.com>,
	<naveen.rao@amd.com>, <tiala@microsoft.com>
Subject: [RFC PATCH v2 06/17] KVM: SVM: Implement interrupt injection for Secure AVIC
Date: Tue, 23 Sep 2025 10:33:06 +0530	[thread overview]
Message-ID: <20250923050317.205482-7-Neeraj.Upadhyay@amd.com> (raw)
In-Reply-To: <20250923050317.205482-1-Neeraj.Upadhyay@amd.com>

For AMD SEV-SNP guests with Secure AVIC, the virtual APIC state is
not visible to KVM and managed by the hardware. This renders the
traditional interrupt injection mechanism, which directly modifies
guest state, unusable. Instead, interrupt delivery must be mediated
through a new interface in the VMCB. Implement support for this
mechanism.

First, new VMCB control fields, requested_irr and update_irr, are
defined to allow KVM to communicate pending interrupts to the hardware
before VMRUN.

Hook the core interrupt injection path, svm_inject_irq(). Instead of
injecting directly, transfer pending interrupts from KVM's software
IRR to the new requested_irr VMCB field and delegate final delivery
to the hardware.

Since the hardware is now responsible for the timing and delivery of
interrupts to the guest (including managing the guest's RFLAGS.IF and
vAPIC state), bypass the standard KVM interrupt window checks in
svm_interrupt_allowed() and svm_enable_irq_window(). Similarly, interrupt
re-injection is handled by the hardware and requires no explicit KVM
involvement.

Finally, update the logic for detecting pending interrupts. Add the
vendor op, protected_apic_has_interrupt(), to check only KVM's software
vAPIC IRR state.

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/lapic.c       | 17 ++++++++++++---
 arch/x86/kvm/svm/sev.c     | 44 ++++++++++++++++++++++++++++++++++++++
 arch/x86/kvm/svm/svm.c     | 13 +++++++++++
 arch/x86/kvm/svm/svm.h     |  4 ++++
 arch/x86/kvm/x86.c         | 15 ++++++++++++-
 6 files changed, 95 insertions(+), 6 deletions(-)

diff --git a/arch/x86/include/asm/svm.h b/arch/x86/include/asm/svm.h
index ab3d55654c77..0faf262f9f9f 100644
--- a/arch/x86/include/asm/svm.h
+++ b/arch/x86/include/asm/svm.h
@@ -162,10 +162,14 @@ struct __attribute__ ((__packed__)) vmcb_control_area {
 	u64 vmsa_pa;		/* Used for an SEV-ES guest */
 	u8 reserved_8[16];
 	u16 bus_lock_counter;		/* Offset 0x120 */
-	u8 reserved_9[22];
+	u8 reserved_9[18];
+	u8 update_irr;			/* Offset 0x134 */
+	u8 reserved_10[3];
 	u64 allowed_sev_features;	/* Offset 0x138 */
 	u64 guest_sev_features;		/* Offset 0x140 */
-	u8 reserved_10[664];
+	u8 reserved_11[8];
+	u32 requested_irr[8];		/* Offset 0x150 */
+	u8 reserved_12[624];
 	/*
 	 * Offset 0x3e0, 32 bytes reserved
 	 * for use by hypervisor/software.
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 5fc437341e03..3199c7c6db05 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -2938,11 +2938,22 @@ int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu)
 	if (!kvm_apic_present(vcpu))
 		return -1;
 
-	if (apic->guest_apic_protected)
+	if (!apic->guest_apic_protected) {
+		__apic_update_ppr(apic, &ppr);
+		return apic_has_interrupt_for_ppr(apic, ppr);
+	}
+
+	if (!apic->prot_apic_intr_inject)
 		return -1;
 
-	__apic_update_ppr(apic, &ppr);
-	return apic_has_interrupt_for_ppr(apic, ppr);
+	/*
+	 * For guest-protected virtual APIC, hardware manages the virtual
+	 * PPR and interrupt delivery to the guest. So, checking the KVM
+	 * managed virtual APIC's APIC_IRR state for any pending vectors
+	 * is the only thing required here.
+	 */
+	return apic_search_irr(apic);
+
 }
 EXPORT_SYMBOL_GPL(kvm_apic_has_interrupt);
 
diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
index afe4127a1918..78cefc14a2ee 100644
--- a/arch/x86/kvm/svm/sev.c
+++ b/arch/x86/kvm/svm/sev.c
@@ -28,6 +28,7 @@
 #include <asm/debugreg.h>
 #include <asm/msr.h>
 #include <asm/sev.h>
+#include <asm/apic.h>
 
 #include "mmu.h"
 #include "x86.h"
@@ -35,6 +36,7 @@
 #include "svm_ops.h"
 #include "cpuid.h"
 #include "trace.h"
+#include "lapic.h"
 
 #define GHCB_VERSION_MAX	2ULL
 #define GHCB_VERSION_DEFAULT	2ULL
@@ -5064,3 +5066,45 @@ void sev_free_decrypted_vmsa(struct kvm_vcpu *vcpu, struct vmcb_save_area *vmsa)
 
 	free_page((unsigned long)vmsa);
 }
+
+void sev_savic_set_requested_irr(struct vcpu_svm *svm, bool reinjected)
+{
+	unsigned int i, vec, vec_pos, vec_start;
+	struct kvm_lapic *apic;
+	bool has_interrupts;
+	u32 val;
+
+	/* 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 = apic_get_reg(apic->regs, APIC_IRR + i * 0x10);
+		if (!val)
+			continue;
+		has_interrupts = true;
+		svm->vmcb->control.requested_irr[i] |= val;
+		vec_start = i * 32;
+		/*
+		 * Clear each vector one by one to avoid race with concurrent
+		 * APIC_IRR updates from the deliver_interrupt() path.
+		 */
+		do {
+			vec_pos = __ffs(val);
+			vec = vec_start + vec_pos;
+			apic_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 064ec98d7e67..7811a87bc111 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -52,6 +52,8 @@
 #include "svm.h"
 #include "svm_ops.h"
 
+#include "lapic.h"
+
 #include "kvm_onhyperv.h"
 #include "svm_onhyperv.h"
 
@@ -3689,6 +3691,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;
@@ -3870,6 +3875,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;
 
@@ -3890,6 +3898,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
@@ -5132,6 +5143,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 1090a48adeda..60dc424d62c4 100644
--- a/arch/x86/kvm/svm/svm.h
+++ b/arch/x86/kvm/svm/svm.h
@@ -873,6 +873,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)
 {
@@ -910,6 +912,8 @@ static inline struct vmcb_save_area *sev_decrypt_vmsa(struct kvm_vcpu *vcpu)
 	return NULL;
 }
 static inline void sev_free_decrypted_vmsa(struct kvm_vcpu *vcpu, struct vmcb_save_area *vmsa) {}
+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 33fba801b205..65ebdc6deb92 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -10369,7 +10369,20 @@ 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 guest-protected VAPIC
+			 * which requires interrupt injection to the guest.
+			 *
+			 * ->inject_irq reads the KVM's VAPIC's APIC_IRR state and
+			 * clears it.
+			 */
+			if (vcpu->arch.apic->guest_apic_protected &&
+			    vcpu->arch.apic->prot_apic_intr_inject)
+				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-09-23  5:05 UTC|newest]

Thread overview: 32+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-09-23  5:03 [RFC PATCH v2 00/17] AMD: Add Secure AVIC KVM Support Neeraj Upadhyay
2025-09-23  5:03 ` [RFC PATCH v2 01/17] KVM: x86/lapic: Differentiate protected APIC interrupt mechanisms Neeraj Upadhyay
2025-09-23  5:03 ` [RFC PATCH v2 02/17] x86/cpufeatures: Add Secure AVIC CPU feature Neeraj Upadhyay
2025-09-23  5:03 ` [RFC PATCH v2 03/17] KVM: SVM: Add support for Secure AVIC capability in KVM Neeraj Upadhyay
2025-09-23  5:03 ` [RFC PATCH v2 04/17] KVM: SVM: Set guest APIC protection flags for Secure AVIC Neeraj Upadhyay
2025-09-23  5:03 ` [RFC PATCH v2 05/17] KVM: SVM: Do not intercept SECURE_AVIC_CONTROL MSR for SAVIC guests Neeraj Upadhyay
2025-09-23 13:55   ` Tom Lendacky
2025-09-25  5:16     ` Upadhyay, Neeraj
2025-09-25 13:54       ` Tom Lendacky
2025-09-23  5:03 ` Neeraj Upadhyay [this message]
2025-09-23 14:47   ` [RFC PATCH v2 06/17] KVM: SVM: Implement interrupt injection for Secure AVIC Tom Lendacky
2025-09-23  5:03 ` [RFC PATCH v2 07/17] KVM: SVM: Add IPI Delivery Support " Neeraj Upadhyay
2025-09-23  5:03 ` [RFC PATCH v2 08/17] KVM: SVM: Do not inject exception " Neeraj Upadhyay
2025-09-23 15:00   ` Tom Lendacky
2025-09-23  5:03 ` [RFC PATCH v2 09/17] KVM: SVM: Do not intercept exceptions for Secure AVIC guests Neeraj Upadhyay
2025-09-23 15:15   ` Tom Lendacky
2025-09-23  5:03 ` [RFC PATCH v2 10/17] KVM: SVM: Set VGIF in VMSA area " Neeraj Upadhyay
2025-09-23 15:16   ` Tom Lendacky
2025-09-23  5:03 ` [RFC PATCH v2 11/17] KVM: SVM: Enable NMI support " Neeraj Upadhyay
2025-09-23 15:25   ` Tom Lendacky
2025-09-23  5:03 ` [RFC PATCH v2 12/17] KVM: SVM: Add VMGEXIT handler for Secure AVIC backing page Neeraj Upadhyay
2025-09-23 16:02   ` Tom Lendacky
2025-09-23  5:03 ` [RFC PATCH v2 13/17] KVM: SVM: Add IOAPIC EOI support for Secure AVIC guests Neeraj Upadhyay
2025-09-23 16:15   ` Tom Lendacky
2025-09-23  5:03 ` [RFC PATCH v2 14/17] KVM: x86/ioapic: Disable RTC EOI tracking for protected APIC guests Neeraj Upadhyay
2025-09-23 16:23   ` Tom Lendacky
2025-09-23  5:03 ` [RFC PATCH v2 15/17] KVM: SVM: Check injected timers for Secure AVIC guests Neeraj Upadhyay
2025-09-23 16:32   ` Tom Lendacky
2025-09-23  5:03 ` [RFC PATCH v2 16/17] KVM: x86/cpuid: Disable paravirt APIC features for protected APIC Neeraj Upadhyay
2025-09-23  5:03 ` [RFC PATCH v2 17/17] KVM: SVM: Advertise Secure AVIC support for SNP guests Neeraj Upadhyay
2025-09-23 10:02 ` [syzbot ci] Re: AMD: Add Secure AVIC KVM Support syzbot ci
2025-09-23 10:17   ` Upadhyay, Neeraj

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=20250923050317.205482-7-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=bp@alien8.de \
    --cc=huibo.wang@amd.com \
    --cc=kvm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=naveen.rao@amd.com \
    --cc=nikunj@amd.com \
    --cc=pbonzini@redhat.com \
    --cc=seanjc@google.com \
    --cc=tiala@microsoft.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