The guest pages of the SEV-SNP VM maybe added as a private page in the RMP entry (assigned bit is set). While terminating the guest we must unassign those pages so that pages are transitioned to the hypervisor state before they can be freed.
Cc: Thomas Gleixner <t...@linutronix.de> Cc: Ingo Molnar <mi...@redhat.com> Cc: Borislav Petkov <b...@alien8.de> Cc: Joerg Roedel <jroe...@suse.de> Cc: "H. Peter Anvin" <h...@zytor.com> Cc: Tony Luck <tony.l...@intel.com> Cc: Dave Hansen <dave.han...@intel.com> Cc: "Peter Zijlstra (Intel)" <pet...@infradead.org> Cc: Paolo Bonzini <pbonz...@redhat.com> Cc: Tom Lendacky <thomas.lenda...@amd.com> Cc: David Rientjes <rient...@google.com> Cc: Sean Christopherson <sea...@google.com> Cc: Vitaly Kuznetsov <vkuzn...@redhat.com> Cc: Wanpeng Li <wanpen...@tencent.com> Cc: Jim Mattson <jmatt...@google.com> Cc: x...@kernel.org Cc: k...@vger.kernel.org Signed-off-by: Brijesh Singh <brijesh.si...@amd.com> --- arch/x86/kvm/svm/sev.c | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c index 1a0c8c95d178..4037430b8d56 100644 --- a/arch/x86/kvm/svm/sev.c +++ b/arch/x86/kvm/svm/sev.c @@ -1517,6 +1517,47 @@ find_enc_region(struct kvm *kvm, struct kvm_enc_region *range) static void __unregister_enc_region_locked(struct kvm *kvm, struct enc_region *region) { + struct rmpupdate val = {}; + unsigned long i, pfn; + rmpentry_t *e; + int level, rc; + + /* + * On SEV-SNP, the guest memory pages are assigned in the RMP table. Un-assigned them + * before releasing the memory. + */ + if (sev_snp_guest(kvm)) { + for (i = 0; i < region->npages; i++) { + pfn = page_to_pfn(region->pages[i]); + + if (need_resched()) + schedule(); + + e = lookup_page_in_rmptable(region->pages[i], &level); + if (!e) { + pr_err("SEV-SNP: failed to read RMP entry (pfn 0x%lx\n", pfn); + continue; + } + + /* If its not a guest assigned page then skip it */ + if (!rmpentry_assigned(e)) + continue; + + /* Is the page part of a 2MB RMP entry? */ + if (level == PG_LEVEL_2M) { + val.pagesize = RMP_PG_SIZE_2M; + pfn &= ~(KVM_PAGES_PER_HPAGE(PG_LEVEL_2M) - 1); + } else { + val.pagesize = RMP_PG_SIZE_4K; + } + + /* Transition the page to hypervisor owned. */ + rc = rmptable_rmpupdate(pfn_to_page(pfn), &val); + if (rc) + pr_err("SEV-SNP: failed to release pfn 0x%lx ret=%d\n", pfn, rc); + } + } + sev_unpin_memory(kvm, region->pages, region->npages); list_del(®ion->list); kfree(region); -- 2.17.1