[RFC Part2 PATCH 19/30] KVM: SVM: Reclaim the guest pages when SEV-SNP VM terminates

From: Brijesh Singh
Date: Wed Mar 24 2021 - 13:06:56 EST


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 <tglx@xxxxxxxxxxxxx>
Cc: Ingo Molnar <mingo@xxxxxxxxxx>
Cc: Borislav Petkov <bp@xxxxxxxxx>
Cc: Joerg Roedel <jroedel@xxxxxxx>
Cc: "H. Peter Anvin" <hpa@xxxxxxxxx>
Cc: Tony Luck <tony.luck@xxxxxxxxx>
Cc: Dave Hansen <dave.hansen@xxxxxxxxx>
Cc: "Peter Zijlstra (Intel)" <peterz@xxxxxxxxxxxxx>
Cc: Paolo Bonzini <pbonzini@xxxxxxxxxx>
Cc: Tom Lendacky <thomas.lendacky@xxxxxxx>
Cc: David Rientjes <rientjes@xxxxxxxxxx>
Cc: Sean Christopherson <seanjc@xxxxxxxxxx>
Cc: Vitaly Kuznetsov <vkuznets@xxxxxxxxxx>
Cc: Wanpeng Li <wanpengli@xxxxxxxxxxx>
Cc: Jim Mattson <jmattson@xxxxxxxxxx>
Cc: x86@xxxxxxxxxx
Cc: kvm@xxxxxxxxxxxxxxx
Signed-off-by: Brijesh Singh <brijesh.singh@xxxxxxx>
---
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(&region->list);
kfree(region);
--
2.17.1