2021-03-24 17:06:51

by Brijesh Singh

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

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 <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Borislav Petkov <[email protected]>
Cc: Joerg Roedel <[email protected]>
Cc: "H. Peter Anvin" <[email protected]>
Cc: Tony Luck <[email protected]>
Cc: Dave Hansen <[email protected]>
Cc: "Peter Zijlstra (Intel)" <[email protected]>
Cc: Paolo Bonzini <[email protected]>
Cc: Tom Lendacky <[email protected]>
Cc: David Rientjes <[email protected]>
Cc: Sean Christopherson <[email protected]>
Cc: Vitaly Kuznetsov <[email protected]>
Cc: Wanpeng Li <[email protected]>
Cc: Jim Mattson <[email protected]>
Cc: [email protected]
Cc: [email protected]
Signed-off-by: Brijesh Singh <[email protected]>
---
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