mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Naveen N Rao <naveen@kernel.org>
To: Sean Christopherson <seanjc@google.com>
Cc: Borislav Petkov <bp@alien8.de>,
	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>,
	 Tianyu Lan <tiala@microsoft.com>,
	Dave Hansen <dave.hansen@linux.intel.com>,
	 Thomas Gleixner <tglx@kernel.org>,
	David Kaplan <david.kaplan@amd.com>,
	 Neeraj Upadhyay <neeraj.upadhyay@kernel.org>,
	Michael Roth <michael.roth@amd.com>
Subject: Re: [RFC PATCH v3 16/27] KVM: SVM: Add handler for VMGEXIT Secure AVIC NAE event
Date: Wed, 30 Sep 2026 20:13:59 +0530	[thread overview]
Message-ID: <arzns-SbdhuGntwm@blrnaveerao1> (raw)
In-Reply-To: <arKHLaVluCNCTaau@blrnaveerao1>

On Tue, Sep 22, 2026 at 08:31:45PM +0530, Naveen N Rao wrote:
> Hi Sean,
> 
> On Wed, Aug 26, 2026 at 09:09:26AM -0700, Sean Christopherson wrote:
> > On Wed, Jul 08, 2026, Naveen N Rao (AMD) wrote:
> > > From: Neeraj Upadhyay <Neeraj.Upadhyay@amd.com>
> > > 
> > > [DO NOT MERGE]
> > > 
> > > VMGEXIT Secure AVIC NAE event is used by the guest for two purposes
> > > determined by VMCB->EXITINFO1:
> > > 1. SVM_VMGEXIT_SAVIC_REGISTER_GPA: Used to inform the hypervisor about
> > >    the GPA of the page (RBX) being used as the Secure AVIC backing page.
> > >    RAX indicates APIC ID of the target vCPU (-1 for self)
> > > 2. SVM_VMGEXIT_SAVIC_UNREGISTER_GPA: Used to inform the hypervisor that
> > >    the GPA is no longer being used as the backing page for Secure AVIC.
> > >    The previously registered GPA for the Secure AVIC backing page is
> > >    returned by the hypervisor to the guest.
> > > 
> > > The primary motivation behind these is to ensure that Secure AVIC
> > > hardware accesses to the guest APIC backing page never generate an #NPF,
> > > since Secure AVIC hardware cannot recover from such faults. Quoting the
> > > APM:
> > >   "It is required that the guest APIC backing page for a vCPU is
> > >    pinned in system memory between VMRUN and VMEXIT because some AVIC
> > >    hardware acceleration sequences may not be restartable when secure
> > >    AVIC is enabled. If an access to the guest's own backing page by
> > >    AVIC hardware results in a nested page fault, EXITINFO1 bit 63
> > >    (Not Restartable) is set (this is an Automatic Exit) and the BUSY
> > >    bit in the VMSA is set."
> > > 
> > > A guest vCPU that has the BUSY bit set in the VMSA cannot be restarted
> > > and the guest will have to be killed.
> > > 
> > > One of the main reasons why the SPTE for a Secure AVIC backing page may
> > > be invalidated is if it is backed by a huge page in the host, and an
> > > adjacent page changes state forcing the huge page to be split. Currently
> > > though, KVM uses guest_memfd to back SEV-SNP guest private memory, and
> > > those only use 4k pages. As such, this _may_ not be an issue today.
> > > 
> > > It is possible that KVM may still invalidate an SPTE for other reasons -
> > > those will need to be addressed.
> > 
> > We _could_ get it working, <snip>

I spent some time to see what this would look like, given that in-place 
conversion has now landed.

> > 
> > However, there are still problems.  E.g. when converting memory, userspace would
> > need to make sure to never do a redundant/superfluous KVM_SET_MEMORY_ATTRIBUTES2
> > on a range that contains a Secure AVIC page, because __kvm_gmem_set_attributes()
> > will tell the MMU to invalidate SHARED mappings for the entire range.  I.e. by
> > design, guest_memfd will not chunk the invalidations based on the per-page state
> > of PRIVATE vs. SHARED, because cross-referencing the current attributes would
> > incur non-trivial complexity.  For TDX, this isn't a problem because the S-EPT
> > is a separate paging structure, and so kvm_gfn_range_filter_to_root_types() can
> > simply skip MIRROR roots to avoid over-zapping PRIVATE memory.  SNP doesn't have
> > such a thing.
> 
> I suppose this is one of the bigger concerns (next to ensuring all 
> invalidation paths are covered). If I'm reading this right, I think 
> your idea (thanks!) to skip zap'ing SPTEs for attribute updates 
> addresses this path:
> https://lore.kernel.org/all/ao9CKMXAX-hScRSa@google.com/
> 
> In fact, as far as I can tell, it likely also addresses the MMU Notifier 
> path independently.

I can confirm that your suggested change above on the current 
kvm-x86/next tree with gmem in-place conversion enabled addresses MMU 
notifier events as well (so Alexandru's patch isn't strictly necessary).

I ended up with a slightly updated if condition to restrict it to SNP:

diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c
index aadd5bdc2c97..195732dbdcce 100644
--- a/arch/x86/kvm/mmu/mmu.c
+++ b/arch/x86/kvm/mmu/mmu.c
@@ -1702,6 +1702,7 @@ static bool __kvm_rmap_zap_gfn_range(struct kvm *kvm,

 bool kvm_unmap_gfn_range(struct kvm *kvm, struct kvm_gfn_range *range)
 {
+       unsigned long shared_private =  KVM_FILTER_SHARED | KVM_FILTER_PRIVATE;
        bool flush = false;

        /*
@@ -1715,6 +1716,21 @@ bool kvm_unmap_gfn_range(struct kvm *kvm, struct kvm_gfn_range *range)
        lockdep_assert_once(kvm->mmu_invalidate_in_progress ||
                            lockdep_is_held(&kvm->slots_lock));

+       /*
+        * Skip zapping pages for to-PRIVATE/to-SHARED conversions for
+        * VMs with non-mirrored roots (SEV-SNP) since the mismatch
+        * between the NPT entry and the HW attribute (RMP) will force
+        * a #NPF, and the subsequent KVM page fault handler or the
+        * RMP fault handler will do the right thing.
+        *
+        * TODO: handle hugepages.
+        */
+       if (gmem_in_place_conversion && kvm_memslot_is_gmem_only(range->slot) &&
+           kvm_arch_has_private_mem(kvm) && kvm->arch.has_protected_state &&
+           !kvm_has_mirrored_tdp(kvm) &&
+           ((range->attr_filter & shared_private) != shared_private))
+               return false;
+

> 
> I believe the other larger concern was ensuring coverage so that there 
> aren't surprises in a production deployment. I was thinking if a check 
> for the Secure AVIC backing page GPA in sev_gmem_invalidate_range() 
> (with a subsequent kvm_vm_dead() or such on a match) can serve as a way 
> to ensure we aren't missing any paths, and to guard against future 
> changes.

With the below hunk, I think we should be able to catch invalidations 
due to PUNCH_HOLE, HWPOISON, memslot DELETE and to-SHARED conversions, 
and should help make the source of the invalidation clear:

diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
index 96992d10cb2b..3c8daa876045 100644
--- a/arch/x86/kvm/svm/sev.c
+++ b/arch/x86/kvm/svm/sev.c
@@ -5571,11 +5571,36 @@ void sev_gmem_invalidate_range(struct kvm *kvm, struct kvm_gfn_range *range)
                 * vCPU to re-establish its VMSA.
                 */
                gpa_t gpa = READ_ONCE(to_svm(vcpu)->sev_es.snp_guest_vmsa_gpa);
+               gpa_t savic_gpa = READ_ONCE(to_svm(vcpu)->sev_es.snp_guest_savic_gpa);

                if (VALID_PAGE(gpa) &&
                    gpa_to_gfn(gpa) >= range->start &&
                    gpa_to_gfn(gpa) < range->end)
                        kvm_make_request_and_kick(KVM_REQ_VMSA_PAGE_RELOAD, vcpu);
+
+               /*
+                * All PRIVATE invalidations that hit the Secure AVIC backing page in
+                * this path will result in a subsequent access by the Secure AVIC HW
+                * to cause a not-restartable #NPF killing the VM. Catch such
+                * invalidations here so that the source of those invalidations is
+                * clear, rather than a subsequent guest access resulting in a
+                * unrecoverable #NPF.
+                *
+                * This is expected on guest teardown, so check if there is a valid
+                * gmem.file before killing the VM.
+                */
+               if (VALID_PAGE(savic_gpa) &&
+                   READ_ONCE(range->slot->gmem.file) &&
+                   (range->attr_filter & KVM_FILTER_PRIVATE) &&
+                   gpa_to_gfn(savic_gpa) >= range->start &&
+                   gpa_to_gfn(savic_gpa) < range->end) {
+                       if (!kvm->vm_dead) {
+                               vcpu_err(vcpu, "Secure AVIC backing page invalidated, GPA 0x%llx!\n", savic_gpa);
+                               dump_stack();
+                               kvm_vm_dead(vcpu->kvm);
+                               return;
+                       }
+               }
        }
 }


The flip side is that this also catches memslot DELETE, which I suppose 
is something we still need to handle (as part of memslot DELETE+CREATE).
In my limited testing so far, I have not been able to hit a scenario 
where this has triggered, so I am not sure how critical or common that 
is during runtime (memslot changes before guest boot should be ok since 
Secure AVIC is not enabled at that point).

One option is to use the below KVM_REQ for memslot DELETE so that the 
target vCPU is kicked out before the invalidation and faults during a 
subsequent prefault (should go out to userspace, but needs to be 
checked). Regardless, we will need some way to suppress the kill in 
gmem_invalidate_range() above for a memslot DELETE.

> 
> > 
> > Converting a subset of a huge PRIVATE page would also be problematic, although
> > that one isn't so bad since we already need to call into the TDP MMU 
> > to pre-split
> > S-EPT pages, because those too can't tolerate spurious zappings.
> 
> For hugepages, the intent is to split as part of the Secure AVIC NAE 
> Event for backing page registration. i.e., PSMASH()+prefault at the time 
> of registration. And since there is no PUNSMASH(), the backing page 
> should never end up as part of a hugepage again.

Regardless of hugepage support, we will still need to prefault the 
backing page on registration to ensure Secure AVIC HW accesses do not 
fault. In addition, it looks like we will also need to prefault the page 
whenever a new NPT root is loaded. This turned out to be the larger 
change and I modeled part of this on KVM_REQ_VMSA_PAGE_RELOAD (diff 
below).

In the absence of hugepage support, this _looks_ to be addressing all 
the invalidation sources (other than memslot DELETE that I mentioned 
earlier) at this time, as far as I can tell.

Are there other invalidation sources we should worry about?

If we want to be super-paranoid, we could add some sort of a hook in 
__handle_changed_spte() though that looks excessive. Hooking into 
kvmmmu/kvm_tdp_mmu_spte_changed tracepoint instead might be a better 
option if we ever hit an unexpected not-restartable #NPF.


Thanks,
Naveen


---
diff --git a/arch/x86/include/asm/kvm-x86-ops.h b/arch/x86/include/asm/kvm-x86-ops.h
index e456564f83da..8f26cf4cbfc0 100644
--- a/arch/x86/include/asm/kvm-x86-ops.h
+++ b/arch/x86/include/asm/kvm-x86-ops.h
@@ -119,6 +119,7 @@ KVM_X86_OP_OPTIONAL(apicv_post_state_restore)
 KVM_X86_OP_OPTIONAL_RET0(dy_apicv_has_pending_interrupt)
 KVM_X86_OP_OPTIONAL(protected_apic_has_interrupt)
 KVM_X86_OP_OPTIONAL(protected_apic_process_interrupt)
+KVM_X86_OP_OPTIONAL_RET0(protected_apic_page_reload)
 KVM_X86_OP_OPTIONAL(set_hv_timer)
 KVM_X86_OP_OPTIONAL(cancel_hv_timer)
 KVM_X86_OP(setup_mce)
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 0e0726cb75f8..e4b880bc68f5 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -128,6 +128,8 @@
 #define KVM_REQ_UPDATE_PROTECTED_GUEST_STATE \
 	KVM_ARCH_REQ_FLAGS(34, KVM_REQUEST_WAIT)
 #define KVM_REQ_PROTECTED_APIC_INTERRUPT	KVM_ARCH_REQ(35)
+#define KVM_REQ_PROTECTED_APIC_PAGE_RELOAD \
+	KVM_ARCH_REQ_FLAGS(36, KVM_REQUEST_WAIT)
 
 #define INVALID_PAGE (~(hpa_t)0)
 #define VALID_PAGE(x) ((x) != INVALID_PAGE)
@@ -1702,6 +1704,7 @@ struct kvm_x86_ops {
 	bool (*dy_apicv_has_pending_interrupt)(struct kvm_vcpu *vcpu);
 	bool (*protected_apic_has_interrupt)(struct kvm_vcpu *vcpu);
 	void (*protected_apic_process_interrupt)(struct kvm_vcpu *vcpu);
+	int (*protected_apic_page_reload)(struct kvm_vcpu *vcpu);
 
 	int (*set_hv_timer)(struct kvm_vcpu *vcpu, u64 guest_deadline_tsc,
 			    bool *expired);
diff --git a/arch/x86/kvm/mmu.h b/arch/x86/kvm/mmu.h
index 2ae7f9ed4cf8..0b611f3f5a21 100644
--- a/arch/x86/kvm/mmu.h
+++ b/arch/x86/kvm/mmu.h
@@ -340,6 +340,7 @@ static inline bool kvm_shadow_root_allocated(struct kvm *kvm)
 }
 
 int kvm_tdp_mmu_map_private_pfn(struct kvm_vcpu *vcpu, gfn_t gfn, kvm_pfn_t pfn);
+int kvm_tdp_mmu_prefault_private_gpa(struct kvm_vcpu *vcpu, gpa_t gpa);
 
 static inline bool kvm_memslots_have_rmaps(struct kvm *kvm)
 {
diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h
index 779cd1013f02..72d30df67795 100644
--- a/arch/x86/kvm/svm/svm.h
+++ b/arch/x86/kvm/svm/svm.h
@@ -273,7 +273,8 @@ struct vcpu_sev_es_state {
 
 	u64 ghcb_registered_gpa;
 
-	gpa_t snp_savic_gpa;
+	gpa_t snp_pending_savic_gpa;
+	gpa_t snp_guest_savic_gpa;
 
 	struct mutex snp_vmsa_mutex; /* Used to handle concurrent updates of VMSA. */
 	gpa_t snp_pending_vmsa_gpa;
@@ -1028,6 +1029,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);
+int snp_protected_apic_page_reload(struct kvm_vcpu *vcpu);
 #else
 static inline struct page *snp_safe_alloc_page_node(int node, gfp_t gfp)
 {
@@ -1056,6 +1058,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 int snp_protected_apic_page_reload(struct kvm_vcpu *vcpu) { return 0; }
 #endif
 
 /* vmenter.S */
diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c
index 195732dbdcce..a83a1c8ca950 100644
--- a/arch/x86/kvm/mmu/mmu.c
+++ b/arch/x86/kvm/mmu/mmu.c
@@ -5327,6 +5327,15 @@ int kvm_tdp_mmu_map_private_pfn(struct kvm_vcpu *vcpu, gfn_t gfn, kvm_pfn_t pfn)
 	return 0;
 }
 EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_tdp_mmu_map_private_pfn);
+
+int kvm_tdp_mmu_prefault_private_gpa(struct kvm_vcpu *vcpu, gpa_t gpa)
+{
+	if (KVM_BUG_ON(kvm_is_gfn_alias(vcpu->kvm, gpa >> PAGE_SHIFT), vcpu->kvm))
+		return -EINVAL;
+
+	return kvm_tdp_page_prefault(vcpu, gpa, PFERR_GUEST_FINAL_MASK | PFERR_PRIVATE_ACCESS, NULL);
+}
+EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_tdp_mmu_prefault_private_gpa);
 #endif
 
 static void nonpaging_init_context(struct kvm_mmu *context)
diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
index f2156850d346..96992d10cb2b 100644
--- a/arch/x86/kvm/svm/sev.c
+++ b/arch/x86/kvm/svm/sev.c
@@ -4595,11 +4595,95 @@ static int savic_handle_ipi_exit(struct kvm_vcpu *vcpu)
 	return 0;
 }
 
+int snp_protected_apic_page_reload(struct kvm_vcpu *vcpu)
+{
+	gpa_t gpa = READ_ONCE(to_svm(vcpu)->sev_es.snp_pending_savic_gpa);
+	int ret;
+
+	/*
+	 * At this point, it is safe to commit the new backing page GPA.
+	 * If replacing a valid GPA, it is up to the guest to ensure that
+	 * the previous backing page GPA has been cleared from the Secure
+	 * AVIC Control MSR before trying to register a new one as
+	 * invalidations will no longer care for the previous GPA.
+	 *
+	 * Publish the GPA under mmu_lock before prefaulting it so that
+	 * no invalidations go through after the prefault.
+	 */
+	scoped_guard(read_lock, &vcpu->kvm->mmu_lock)
+		WRITE_ONCE(to_svm(vcpu)->sev_es.snp_guest_savic_gpa, gpa);
+
+	/* Unregistration */
+	if (gpa == INVALID_PAGE)
+		return 0;
+
+	ret = kvm_tdp_mmu_prefault_private_gpa(vcpu, gpa);
+
+	if (ret == -EINTR)
+		kvm_handle_signal_exit(vcpu);
+
+	if (ret) {
+		kvm_make_request(KVM_REQ_PROTECTED_APIC_PAGE_RELOAD, vcpu);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int savic_handle_vmgexit_register_gpa(struct kvm_vcpu *target_vcpu, gpa_t gpa)
+{
+	struct kvm *kvm = target_vcpu->kvm;
+	struct kvm_memory_slot *slot;
+	unsigned long mmu_seq;
+	int order, rmp_level, ret;
+	kvm_pfn_t pfn;
+	bool assigned;
+	gfn_t gfn;
+
+	gfn = gpa >> PAGE_SHIFT;
+
+	if (!page_address_valid(target_vcpu, gpa))
+		return -EINVAL;
+
+retry:
+	cond_resched();
+
+	mmu_seq = kvm->mmu_invalidate_seq;
+	smp_rmb();
+
+	slot = gfn_to_memslot(kvm, gfn);
+	if (!kvm_is_private_gfn(kvm, gfn) || !kvm_slot_has_gmem(slot))
+		return -EINVAL;
+
+	ret = kvm_gmem_get_pfn(kvm, slot, gfn, &pfn, &order);
+	if (ret)
+		return -EINVAL;
+
+	ret = snp_lookup_rmpentry(pfn, &assigned, &rmp_level);
+	if (ret || !assigned) {
+		guard(read_lock)(&kvm->mmu_lock);
+
+		if (mmu_invalidate_retry_gfn(kvm, mmu_seq, gfn))
+			goto retry;
+
+		return -EINVAL;
+	}
+
+	if (WARN_ON_ONCE(rmp_level != PG_LEVEL_4K))
+		return -EOPNOTSUPP;
+
+	WRITE_ONCE(to_svm(target_vcpu)->sev_es.snp_pending_savic_gpa, gpa);
+	kvm_make_request_and_kick(KVM_REQ_PROTECTED_APIC_PAGE_RELOAD, target_vcpu);
+
+	return 0;
+}
+
 static int sev_handle_savic_vmgexit(struct vcpu_svm *svm)
 {
 	struct kvm_vcpu *target_vcpu;
 	u64 apic_id;
 	gpa_t gpa;
+	int ret;
 
 	apic_id = kvm_rax_read_raw(&svm->vcpu);
 	if (apic_id != SVM_VMGEXIT_SAVIC_SELF_GPA && upper_32_bits(apic_id))
@@ -4616,27 +4700,14 @@ static int sev_handle_savic_vmgexit(struct vcpu_svm *svm)
 	switch (svm->vmcb->control.exit_info_1) {
 	case SVM_VMGEXIT_SAVIC_REGISTER_GPA:
 		gpa = kvm_rbx_read_raw(&svm->vcpu);
-		if (!page_address_valid(target_vcpu, gpa))
+		ret = savic_handle_vmgexit_register_gpa(target_vcpu, gpa);
+		if (ret)
 			goto vmgexit_err;
-
-		/*
-		 * TODO: Ensure that guest (Secure AVIC hardware) accesses
-		 * to the guest APIC backing page can never cause an #NPF.
-		 */
-
-		/*
-		 * Don't bother using any synchronization here if updating the
-		 * GPA for a different vCPU, to guard against potential
-		 * concurrent requests from different guest vCPUs. KVM's
-		 * handling for this will inform what synchronization,
-		 * if any will be necessary.
-		 */
-		to_svm(target_vcpu)->sev_es.snp_savic_gpa = gpa;
 		break;
 	case SVM_VMGEXIT_SAVIC_UNREGISTER_GPA:
-		gpa = to_svm(target_vcpu)->sev_es.snp_savic_gpa;
+		gpa = xchg(&to_svm(target_vcpu)->sev_es.snp_pending_savic_gpa, INVALID_PAGE);
 		kvm_rbx_write_raw(&svm->vcpu, gpa == INVALID_PAGE ? 0 : gpa);
-		to_svm(target_vcpu)->sev_es.snp_savic_gpa = INVALID_PAGE;
+		kvm_make_request_and_kick(KVM_REQ_PROTECTED_APIC_PAGE_RELOAD, target_vcpu);
 		break;
 	default:
 		goto vmgexit_err;
@@ -5076,7 +5147,8 @@ int sev_vcpu_create(struct kvm_vcpu *vcpu)
 	svm->sev_es.snp_pending_vmsa_gpa = INVALID_PAGE;
 	svm->sev_es.snp_guest_vmsa_gpa = INVALID_PAGE;
 
-	svm->sev_es.snp_savic_gpa = INVALID_PAGE;
+	svm->sev_es.snp_pending_savic_gpa = INVALID_PAGE;
+	svm->sev_es.snp_guest_savic_gpa = INVALID_PAGE;
 
 	vcpu->arch.guest_tsc_protected = snp_is_secure_tsc_enabled(vcpu->kvm);
 
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index 18d061a157c2..6909d2c645a9 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -2008,7 +2008,7 @@ static int npf_interception(struct kvm_vcpu *vcpu)
 
 	u64 error_code = svm->vmcb->control.exit_info_1;
 	gpa_t gpa = svm->vmcb->control.exit_info_2;
-	gpa_t savic_gpa = svm->sev_es.snp_savic_gpa;
+	gpa_t savic_gpa = svm->sev_es.snp_guest_savic_gpa;
 
 	if (error_code & PFERR_SNP_NOT_RESTARTABLE_MASK) {
 		if (VALID_PAGE(savic_gpa) && (gpa_to_gfn(gpa) == gpa_to_gfn(savic_gpa)))
@@ -4848,6 +4848,9 @@ static void svm_load_mmu_pgd(struct kvm_vcpu *vcpu, hpa_t root_hpa,
 		hv_track_root_tdp(vcpu, root_hpa);
 
 		cr3 = vcpu->arch.cr3;
+
+		if (snp_is_secure_avic_enabled(vcpu->kvm))
+			kvm_make_request(KVM_REQ_PROTECTED_APIC_PAGE_RELOAD, vcpu);
 	} else if (root_level >= PT64_ROOT_4LEVEL) {
 		cr3 = __sme_set(root_hpa) | kvm_get_active_pcid(vcpu);
 	} else {
@@ -5597,6 +5600,7 @@ struct kvm_x86_ops svm_x86_ops __initdata = {
 
 	.protected_apic_has_interrupt = avic_protected_apic_has_interrupt,
 	.protected_apic_process_interrupt = avic_protected_apic_process_interrupt,
+	.protected_apic_page_reload = snp_protected_apic_page_reload,
 
 	.get_exit_info = svm_get_exit_info,
 	.get_entry_info = svm_get_entry_info,
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 3384a1b215ef..897dca49e2c1 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -8240,6 +8240,12 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
 
 		if (kvm_check_request(KVM_REQ_PROTECTED_APIC_INTERRUPT, vcpu))
 			kvm_x86_call(protected_apic_process_interrupt)(vcpu);
+
+		if (kvm_check_request(KVM_REQ_PROTECTED_APIC_PAGE_RELOAD, vcpu)) {
+			r = kvm_x86_call(protected_apic_page_reload)(vcpu);
+			if (r)
+				goto out;
+		}
 	}
 
 	if (kvm_check_request(KVM_REQ_EVENT, vcpu) || req_int_win ||



  reply	other threads:[~2026-09-30 14:47 UTC|newest]

Thread overview: 47+ 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-08-26 16:09   ` Sean Christopherson
2026-09-22 15:01     ` Naveen N Rao
2026-09-30 14:43       ` Naveen N Rao [this message]
2026-09-30 15:45         ` Sean Christopherson
2026-09-30 19:54           ` Naveen N Rao
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 ` [RFC PATCH v3 21/27] KVM: SVM: Add interrupt delivery support for Secure AVIC guests Naveen N Rao (AMD)
2026-07-08  6:32 ` [RFC PATCH v3 22/27] KVM: SVM: Add support for incomplete IPI handling for Secure AVIC 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=arzns-SbdhuGntwm@blrnaveerao1 \
    --to=naveen@kernel.org \
    --cc=bp@alien8.de \
    --cc=dave.hansen@linux.intel.com \
    --cc=david.kaplan@amd.com \
    --cc=kvm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=michael.roth@amd.com \
    --cc=neeraj.upadhyay@kernel.org \
    --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

all inboxes | Powered by JetHome®