[RFC PATCH v3 19/27] KVM: SVM: Implement kvm_x86_ops->protected_apic_has_injectable_intr() for Secure AVIC

From: Naveen N Rao (AMD)

Date: Wed Jul 08 2026 - 02:49:09 EST


KVM tracks interrupts to be injected for a Secure AVIC enabled guest in
its copy of the APIC_IRR. Consequently, checking if an interrupt is
pending injection just requires checking KVM's copy of the APIC_IRR. Wire
up protected_apic_has_injectable_intr() to do so.

Signed-off-by: Naveen N Rao (AMD) <naveen@xxxxxxxxxx>
---
arch/x86/kvm/svm/svm.h | 2 ++
arch/x86/kvm/svm/sev.c | 6 ++++++
arch/x86/kvm/svm/svm.c | 2 ++
3 files changed, 10 insertions(+)

diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h
index 5e9496f8566a..af3c84a61c07 100644
--- a/arch/x86/kvm/svm/svm.h
+++ b/arch/x86/kvm/svm/svm.h
@@ -1017,6 +1017,7 @@ int sev_gmem_max_mapping_level(struct kvm *kvm, kvm_pfn_t pfn, bool is_private);
struct vmcb_save_area *sev_decrypt_vmsa(struct kvm_vcpu *vcpu);
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);
#else
static inline struct page *snp_safe_alloc_page_node(int node, gfp_t gfp)
{
@@ -1055,6 +1056,7 @@ static inline struct vmcb_save_area *sev_decrypt_vmsa(struct kvm_vcpu *vcpu)
}
static inline void sev_free_decrypted_vmsa(struct kvm_vcpu *vcpu, struct vmcb_save_area *vmsa) {}
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; }
#endif

/* vmenter.S */
diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
index ca921a185b64..3d36168c3327 100644
--- a/arch/x86/kvm/svm/sev.c
+++ b/arch/x86/kvm/svm/sev.c
@@ -35,6 +35,7 @@
#include "svm_ops.h"
#include "cpuid.h"
#include "trace.h"
+#include "lapic.h"

#define GHCB_VERSION_MAX 2ULL
#define GHCB_VERSION_MIN 1ULL
@@ -4941,6 +4942,11 @@ void sev_es_prepare_switch_to_guest(struct vcpu_svm *svm, struct sev_es_save_are
hostsa->tsc_aux = kvm_get_user_return_msr(tsc_aux_uret_slot);
}

+bool snp_protected_apic_has_injectable_intr(struct kvm_vcpu *vcpu)
+{
+ return apic_find_highest_vector(vcpu->arch.apic->regs + APIC_IRR) != -1;
+}
+
void sev_vcpu_deliver_sipi_vector(struct kvm_vcpu *vcpu, u8 vector)
{
struct vcpu_svm *svm = to_svm(vcpu);
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index 0e0dd9618750..441520c1312d 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -5398,6 +5398,8 @@ 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_injectable_intr = snp_protected_apic_has_injectable_intr,
+
.get_exit_info = svm_get_exit_info,
.get_entry_info = svm_get_entry_info,

--
2.54.0