|
@@ -611,6 +611,71 @@ static void unmap_stage2_range(struct kvm *kvm, phys_addr_t start, u64 size)
|
|
|
unmap_range(kvm, kvm->arch.pgd, start, size);
|
|
|
}
|
|
|
|
|
|
+static void stage2_unmap_memslot(struct kvm *kvm,
|
|
|
+ struct kvm_memory_slot *memslot)
|
|
|
+{
|
|
|
+ hva_t hva = memslot->userspace_addr;
|
|
|
+ phys_addr_t addr = memslot->base_gfn << PAGE_SHIFT;
|
|
|
+ phys_addr_t size = PAGE_SIZE * memslot->npages;
|
|
|
+ hva_t reg_end = hva + size;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * A memory region could potentially cover multiple VMAs, and any holes
|
|
|
+ * between them, so iterate over all of them to find out if we should
|
|
|
+ * unmap any of them.
|
|
|
+ *
|
|
|
+ * +--------------------------------------------+
|
|
|
+ * +---------------+----------------+ +----------------+
|
|
|
+ * | : VMA 1 | VMA 2 | | VMA 3 : |
|
|
|
+ * +---------------+----------------+ +----------------+
|
|
|
+ * | memory region |
|
|
|
+ * +--------------------------------------------+
|
|
|
+ */
|
|
|
+ do {
|
|
|
+ struct vm_area_struct *vma = find_vma(current->mm, hva);
|
|
|
+ hva_t vm_start, vm_end;
|
|
|
+
|
|
|
+ if (!vma || vma->vm_start >= reg_end)
|
|
|
+ break;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Take the intersection of this VMA with the memory region
|
|
|
+ */
|
|
|
+ vm_start = max(hva, vma->vm_start);
|
|
|
+ vm_end = min(reg_end, vma->vm_end);
|
|
|
+
|
|
|
+ if (!(vma->vm_flags & VM_PFNMAP)) {
|
|
|
+ gpa_t gpa = addr + (vm_start - memslot->userspace_addr);
|
|
|
+ unmap_stage2_range(kvm, gpa, vm_end - vm_start);
|
|
|
+ }
|
|
|
+ hva = vm_end;
|
|
|
+ } while (hva < reg_end);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * stage2_unmap_vm - Unmap Stage-2 RAM mappings
|
|
|
+ * @kvm: The struct kvm pointer
|
|
|
+ *
|
|
|
+ * Go through the memregions and unmap any reguler RAM
|
|
|
+ * backing memory already mapped to the VM.
|
|
|
+ */
|
|
|
+void stage2_unmap_vm(struct kvm *kvm)
|
|
|
+{
|
|
|
+ struct kvm_memslots *slots;
|
|
|
+ struct kvm_memory_slot *memslot;
|
|
|
+ int idx;
|
|
|
+
|
|
|
+ idx = srcu_read_lock(&kvm->srcu);
|
|
|
+ spin_lock(&kvm->mmu_lock);
|
|
|
+
|
|
|
+ slots = kvm_memslots(kvm);
|
|
|
+ kvm_for_each_memslot(memslot, slots)
|
|
|
+ stage2_unmap_memslot(kvm, memslot);
|
|
|
+
|
|
|
+ spin_unlock(&kvm->mmu_lock);
|
|
|
+ srcu_read_unlock(&kvm->srcu, idx);
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* kvm_free_stage2_pgd - free all stage-2 tables
|
|
|
* @kvm: The KVM struct pointer for the VM.
|