From: "Naveen N Rao (AMD)" <naveen@kernel.org>
To: Sean Christopherson <seanjc@google.com>, Borislav Petkov <bp@alien8.de>
Cc: <kvm@vger.kernel.org>, <linux-kernel@vger.kernel.org>,
Paolo Bonzini <pbonzini@redhat.com>,
Nikunj A Dadhania <nikunj@amd.com>,
Tom Lendacky <thomas.lendacky@amd.com>,
Neeraj Upadhyay <neeraj.upadhyay@amd.com>,
Tianyu Lan <tiala@microsoft.com>,
Dave Hansen <dave.hansen@linux.intel.com>,
Thomas Gleixner <tglx@kernel.org>
Subject: [RFC PATCH v3 21/27] KVM: SVM: Add interrupt delivery support for Secure AVIC guests
Date: Wed, 8 Jul 2026 12:02:19 +0530 [thread overview]
Message-ID: <46920d50baf7a8a333579beda6f6b2645b5ee4cd.1783490022.git.naveen@kernel.org> (raw)
In-Reply-To: <cover.1783490022.git.naveen@kernel.org>
To inject an interrupt into a Secure AVIC enabled guest, KVM needs to:
- set the vector in VMCB->requested_irr (VMCB offset 0x150), which is a
contiguous 256-bit field representing vectors that the hypervisor
wants to inject into the guest.
- set VMCB->update_irr (VMCB offset 0x134) so hardware knows to process
requested_irr from the VMCB, and
- invoke VMRUN.
As the field name suggests, KVM can only "request" for interrupts to be
injected into the guest. Guest is free to ignore vectors it does not
want to accept from the hypervisor, and it controls which vectors are
actually accepted by setting up allowed_irr field in its private APIC
backing page (8 32-bit APIC registers following APIC_IRR in the backing
page).
On VMRUN, hardware updates APIC_IRR in the private guest APIC backing
page based on update_irr/requested_irr in the VMCB and allowed_irr in
the guest APIC backing page, and then clears VMCB fields update_irr and
requested_irr.
Because hardware clears requested_irr and update_irr in the VMCB on
VMRUN in no particular order, KVM can't stuff incoming vectors directly
into the VMCB fields. Instead, park vectors to be injected into the
guest in KVM's copy of the APIC_IRR (already done in the default flow in
svm_deliver_interrupt()).
Since Secure AVIC requires interrupts to be injected through the VMCB,
do not use AVIC doorbells for interrupt delivery. Instead rely on the
non-AVIC flow in svm_complete_interrupt_delivery() to set KVM_REQ_EVENT
and kick the vCPU.
Before VM entry, KVM invokes svm_inject_irq() (since APIC_IRR has
vectors to be injected, and since kvm_cpu_has_injectable_intr() returns
true), at which point transfer all pending interrupt vectors from KVM's
APIC_IRR to VMCB->requested_irr and set VMCB->update_irr. Atomically
clear APIC_IRR so that incoming interrupt vectors are not lost. Also
update vCPU irq_injection stats and optionally invoke the corresponding
tracepoint if enabled (its debatable whether kvm_apicv_accept_irq
tracepoint should be invoked instead).
Finally, always return true for interrupt_allowed() since KVM has no
visibility into the guest APIC state and KVM can simply pend interrupts
in requested_irr at any point. Return early from svm_enable_irq_window()
for the same reason -- KVM has no visibility into that.
Co-developed-by: Kishon Vijay Abraham I <kvijayab@amd.com>
Signed-off-by: Kishon Vijay Abraham I <kvijayab@amd.com>
Co-developed-by: Neeraj Upadhyay <Neeraj.Upadhyay@amd.com>
Signed-off-by: Neeraj Upadhyay <Neeraj.Upadhyay@amd.com>
Signed-off-by: Naveen N Rao (AMD) <naveen@kernel.org>
---
arch/x86/include/asm/svm.h | 7 +++++--
arch/x86/kvm/svm/svm.h | 2 ++
arch/x86/kvm/svm/sev.c | 27 +++++++++++++++++++++++++++
arch/x86/kvm/svm/svm.c | 25 ++++++++++++++++++++++++-
4 files changed, 58 insertions(+), 3 deletions(-)
diff --git a/arch/x86/include/asm/svm.h b/arch/x86/include/asm/svm.h
index 5857b942957b..b4a803686e0b 100644
--- a/arch/x86/include/asm/svm.h
+++ b/arch/x86/include/asm/svm.h
@@ -162,10 +162,13 @@ 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];
+ u32 update_irr; /* Offset 0x134 */
u64 allowed_sev_features; /* Offset 0x138 */
u64 guest_sev_features; /* Offset 0x140 */
- u8 reserved_10[664];
+ u8 reserved_10[8];
+ 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/svm/svm.h b/arch/x86/kvm/svm/svm.h
index f5e270086b51..44f1d25a167c 100644
--- a/arch/x86/kvm/svm/svm.h
+++ b/arch/x86/kvm/svm/svm.h
@@ -1019,6 +1019,7 @@ void sev_free_decrypted_vmsa(struct kvm_vcpu *vcpu, struct vmcb_save_area *vmsa)
bool snp_is_secure_avic_enabled(struct kvm *kvm);
bool snp_protected_apic_has_injectable_intr(struct kvm_vcpu *vcpu);
bool snp_protected_apic_has_interrupt(struct kvm_vcpu *vcpu);
+void savic_update_requested_irr(struct kvm_vcpu *vcpu);
#else
static inline struct page *snp_safe_alloc_page_node(int node, gfp_t gfp)
{
@@ -1059,6 +1060,7 @@ static inline void sev_free_decrypted_vmsa(struct kvm_vcpu *vcpu, struct vmcb_sa
static inline bool snp_is_secure_avic_enabled(struct kvm *kvm) { return false; }
static inline bool snp_protected_apic_has_injectable_intr(struct kvm_vcpu *vcpu) { return false; }
static inline bool snp_protected_apic_has_interrupt(struct kvm_vcpu *vcpu) { return false; }
+static inline void savic_update_requested_irr(struct kvm_vcpu *vcpu) {}
#endif
/* vmenter.S */
diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
index a0c5271ec4ca..754fe12c2f82 100644
--- a/arch/x86/kvm/svm/sev.c
+++ b/arch/x86/kvm/svm/sev.c
@@ -4428,6 +4428,33 @@ static int sev_handle_vmgexit_msr_protocol(struct vcpu_svm *svm)
return 0;
}
+void savic_update_requested_irr(struct kvm_vcpu *vcpu)
+{
+ struct vcpu_svm *svm = to_svm(vcpu);
+ u32 *apic_irr, irr;
+
+ for (int i = 0; i < APIC_ISR_NR; i++) {
+ apic_irr = (u32 *)(vcpu->arch.apic->regs + APIC_IRR + i * 0x10);
+
+ if (!READ_ONCE(*apic_irr))
+ continue;
+
+ irr = xchg(apic_irr, 0);
+ svm->vmcb->control.requested_irr[i] |= irr;
+ vcpu->stat.irq_injections += hweight32(irr);
+
+ if (trace_kvm_inj_virq_enabled()) {
+ unsigned long irr_injected = irr;
+ unsigned int vector;
+
+ for_each_set_bit(vector, &irr_injected, BITS_PER_TYPE(irr))
+ trace_kvm_inj_virq(i * 32 + vector, false, false);
+ }
+ }
+
+ WRITE_ONCE(svm->vmcb->control.update_irr, 1);
+}
+
static int sev_handle_savic_vmgexit(struct vcpu_svm *svm)
{
struct kvm_vcpu *target_vcpu;
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index 3f731483f6a2..612cc4ac9bd2 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -3824,6 +3824,11 @@ static void svm_inject_irq(struct kvm_vcpu *vcpu, bool reinjected)
struct vcpu_svm *svm = to_svm(vcpu);
u32 type;
+ if (snp_is_secure_avic_enabled(vcpu->kvm)) {
+ savic_update_requested_irr(vcpu);
+ return;
+ }
+
if (intr->soft) {
if (svm_update_soft_interrupt_rip(vcpu, intr->nr))
return;
@@ -3896,7 +3901,7 @@ void svm_complete_interrupt_delivery(struct kvm_vcpu *vcpu, int delivery_mode,
bool in_guest_mode = (smp_load_acquire(&vcpu->mode) == IN_GUEST_MODE);
/* Note, this is called iff the local APIC is in-kernel. */
- if (!READ_ONCE(vcpu->arch.apic->apicv_active)) {
+ if (!READ_ONCE(vcpu->arch.apic->apicv_active) || snp_is_secure_avic_enabled(vcpu->kvm)) {
/* Process the interrupt via kvm_check_and_inject_events(). */
kvm_make_request(KVM_REQ_EVENT, vcpu);
kvm_vcpu_kick(vcpu);
@@ -4050,6 +4055,14 @@ static int svm_interrupt_allowed(struct kvm_vcpu *vcpu, bool for_injection)
{
struct vcpu_svm *svm = to_svm(vcpu);
+ /*
+ * KVM does not have access to the Secure AVIC guest APIC backing page.
+ * The only thing KVM can do is to queue up interrupts in the VMCB
+ * (Requested_IRR), which is always allowed.
+ */
+ if (snp_is_secure_avic_enabled(vcpu->kvm))
+ return 1;
+
if (svm_interrupt_blocked(vcpu))
return 0;
@@ -4070,6 +4083,16 @@ static void svm_enable_irq_window(struct kvm_vcpu *vcpu)
{
struct vcpu_svm *svm = to_svm(vcpu);
+ /*
+ * Secure AVIC does not allow VINTR, so we can't request an interrupt
+ * window. The only reason we end up here is if an interrupt arrived
+ * just as we injected pending interrupts (from
+ * kvm_check_and_inject_events()). Ignore and proceed, any pending
+ * interrupt(s) will be re-injected on next entry.
+ */
+ if (snp_is_secure_avic_enabled(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
--
2.54.0
next prev parent reply other threads:[~2026-07-08 6:34 UTC|newest]
Thread overview: 42+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-08 6:31 [RFC PATCH v3 00/27] KVM: SVM: Add support for SEV-SNP Secure AVIC Naveen N Rao (AMD)
2026-07-08 6:31 ` [RFC PATCH v3 01/27] x86/apic: Propagate APIC_SPIV writes to hv for " Naveen N Rao (AMD)
2026-07-10 2:03 ` Borislav Petkov
2026-07-10 15:02 ` Naveen N Rao
2026-07-11 4:37 ` Borislav Petkov
2026-07-13 17:38 ` Tom Lendacky
2026-07-14 8:57 ` Naveen N Rao
2026-07-08 6:32 ` [RFC PATCH v3 02/27] x86/apic: Drop savic_eoi() in favor of native_apic_msr_eoi() " Naveen N Rao (AMD)
2026-07-13 17:43 ` Tom Lendacky
2026-07-14 9:02 ` Naveen N Rao
2026-07-08 6:32 ` [RFC PATCH v3 03/27] x86/kvm: Disable PV_SEND_IPI if Secure AVIC is enabled Naveen N Rao (AMD)
2026-07-13 17:52 ` Tom Lendacky
2026-07-14 9:42 ` Naveen N Rao
2026-07-08 6:32 ` [RFC PATCH v3 04/27] x86/apic: Use AVIC_INCOMPLETE_IPI VMGEXIT for Secure AVIC IPI handling Naveen N Rao (AMD)
2026-07-13 17:59 ` Tom Lendacky
2026-07-14 10:03 ` Naveen N Rao
2026-07-08 6:32 ` [RFC PATCH v3 05/27] x86/cpufeatures: Add Secure AVIC CPU feature Naveen N Rao (AMD)
2026-07-13 18:32 ` Tom Lendacky
2026-07-08 6:32 ` [RFC PATCH v3 06/27] KVM: SVM: Add helper to check if Secure AVIC is enabled for a guest Naveen N Rao (AMD)
2026-07-13 18:35 ` Tom Lendacky
2026-07-08 6:32 ` [RFC PATCH v3 07/27] KVM: SVM: Set guest_apic_protected if Secure AVIC is enabled Naveen N Rao (AMD)
2026-07-08 6:32 ` [RFC PATCH v3 08/27] kvm: irqfd: Have kvm_arch_has_irq_bypass() take struct kvm pointer Naveen N Rao (AMD)
2026-07-08 6:32 ` [RFC PATCH v3 09/27] KVM: SVM: Disable IRQ bypass for Secure AVIC Naveen N Rao (AMD)
2026-07-08 6:32 ` [RFC PATCH v3 10/27] KVM: SVM: Add avic_ipiv_is_soft_disabled() as a wrapper around enable_ipiv Naveen N Rao (AMD)
2026-07-08 6:32 ` [RFC PATCH v3 11/27] KVM: SVM: Disable IPIv for Secure AVIC Naveen N Rao (AMD)
2026-07-08 6:32 ` [RFC PATCH v3 12/27] KVM: SVM: Short-circuit a few AVIC flows " Naveen N Rao (AMD)
2026-07-08 6:32 ` [RFC PATCH v3 13/27] KVM: SVM: Warn if we ever receive AVIC_UNACCELERATED_ACCESS #VMEXIT Naveen N Rao (AMD)
2026-07-08 6:32 ` [RFC PATCH v3 14/27] KVM: SVM: Do not inhibit AVIC for SEV-SNP guests if Secure AVIC is enabled Naveen N Rao (AMD)
2026-07-08 6:32 ` [RFC PATCH v3 15/27] KVM: SVM: Set VGIF in VMSA area for Secure AVIC guests Naveen N Rao (AMD)
2026-07-08 6:32 ` [RFC PATCH v3 16/27] KVM: SVM: Add handler for VMGEXIT Secure AVIC NAE event Naveen N Rao (AMD)
2026-07-08 6:32 ` [RFC PATCH v3 17/27] KVM: SVM: Do not intercept SECURE_AVIC_CONTROL MSR for Secure AVIC guests Naveen N Rao (AMD)
2026-07-08 6:32 ` [RFC PATCH v3 18/27] KVM: x86: Add a new kvm_x86_op protected_apic_has_injectable_intr() Naveen N Rao (AMD)
2026-07-08 6:32 ` [RFC PATCH v3 19/27] KVM: SVM: Implement kvm_x86_ops->protected_apic_has_injectable_intr() for Secure AVIC Naveen N Rao (AMD)
2026-07-08 6:32 ` [RFC PATCH v3 20/27] KVM: SVM: Implement kvm_x86_ops->protected_apic_has_interrupt() " Naveen N Rao (AMD)
2026-07-08 6:32 ` Naveen N Rao (AMD) [this message]
2026-07-08 6:32 ` [RFC PATCH v3 22/27] KVM: SVM: Add support for incomplete IPI handling " Naveen N Rao (AMD)
2026-07-08 6:32 ` [RFC PATCH v3 23/27] KVM: SVM: Add support for injecting NMIs for Secure AVIC guests Naveen N Rao (AMD)
2026-07-08 6:32 ` [RFC PATCH v3 24/27] KVM: SVM: Mandate use of split irqchip for Secure AVIC Naveen N Rao (AMD)
2026-07-08 6:32 ` [RFC PATCH v3 25/27] KVM: SVM: Do not inject exceptions " Naveen N Rao (AMD)
2026-07-08 6:32 ` [RFC PATCH v3 26/27] KVM: SVM: Do not intercept exceptions for Secure AVIC guests Naveen N Rao (AMD)
2026-07-08 6:32 ` [RFC PATCH v3 27/27] KVM: SVM: Advertise Secure AVIC support for SEV-SNP guests Naveen N Rao (AMD)
2026-07-08 9:20 ` [RFC PATCH v3 00/27] KVM: SVM: Add support for SEV-SNP Secure AVIC Naveen N Rao
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=46920d50baf7a8a333579beda6f6b2645b5ee4cd.1783490022.git.naveen@kernel.org \
--to=naveen@kernel.org \
--cc=bp@alien8.de \
--cc=dave.hansen@linux.intel.com \
--cc=kvm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=neeraj.upadhyay@amd.com \
--cc=nikunj@amd.com \
--cc=pbonzini@redhat.com \
--cc=seanjc@google.com \
--cc=tglx@kernel.org \
--cc=thomas.lendacky@amd.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
Powered by JetHome