Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

KVM: PPC: Book3S HV: In H_SVM_INIT_DONE, migrate remaining normal-GFNs to secure-GFNs

The Ultravisor is expected to explicitly call H_SVM_PAGE_IN for all the
pages of the SVM before calling H_SVM_INIT_DONE. This causes a huge
delay in tranistioning the VM to SVM. The Ultravisor is only interested
in the pages that contain the kernel, initrd and other important data
structures. The rest contain throw-away content.

However if not all pages are requested by the Ultravisor, the Hypervisor
continues to consider the GFNs corresponding to the non-requested pages
as normal GFNs. This can lead to data-corruption and undefined behavior.

In H_SVM_INIT_DONE handler, move all the PFNs associated with the SVM's
GFNs to secure-PFNs. Skip the GFNs that are already Paged-in or Shared
or Paged-in followed by a Paged-out.

Reviewed-by: Bharata B Rao <bharata@linux.ibm.com>
Signed-off-by: Ram Pai <linuxram@us.ibm.com>
Signed-off-by: Paul Mackerras <paulus@ozlabs.org>

authored by

Ram Pai and committed by
Paul Mackerras
dfaa973a 651a6310

+134 -22
+2
Documentation/powerpc/ultravisor.rst
··· 934 934 * H_UNSUPPORTED if called from the wrong context (e.g. 935 935 from an SVM or before an H_SVM_INIT_START 936 936 hypercall). 937 + * H_STATE if the hypervisor could not successfully 938 + transition the VM to Secure VM. 937 939 938 940 Description 939 941 ~~~~~~~~~~~
+132 -22
arch/powerpc/kvm/book3s_hv_uvmem.c
··· 93 93 #include <asm/ultravisor.h> 94 94 #include <asm/mman.h> 95 95 #include <asm/kvm_ppc.h> 96 + #include <asm/kvm_book3s_uvmem.h> 96 97 97 98 static struct dev_pagemap kvmppc_uvmem_pgmap; 98 99 static unsigned long *kvmppc_uvmem_bitmap; ··· 349 348 return false; 350 349 } 351 350 351 + /* 352 + * starting from *gfn search for the next available GFN that is not yet 353 + * transitioned to a secure GFN. return the value of that GFN in *gfn. If a 354 + * GFN is found, return true, else return false 355 + * 356 + * Must be called with kvm->arch.uvmem_lock held. 357 + */ 358 + static bool kvmppc_next_nontransitioned_gfn(const struct kvm_memory_slot *memslot, 359 + struct kvm *kvm, unsigned long *gfn) 360 + { 361 + struct kvmppc_uvmem_slot *p; 362 + bool ret = false; 363 + unsigned long i; 364 + 365 + list_for_each_entry(p, &kvm->arch.uvmem_pfns, list) 366 + if (*gfn >= p->base_pfn && *gfn < p->base_pfn + p->nr_pfns) 367 + break; 368 + if (!p) 369 + return ret; 370 + /* 371 + * The code below assumes, one to one correspondence between 372 + * kvmppc_uvmem_slot and memslot. 373 + */ 374 + for (i = *gfn; i < p->base_pfn + p->nr_pfns; i++) { 375 + unsigned long index = i - p->base_pfn; 376 + 377 + if (!(p->pfns[index] & KVMPPC_GFN_FLAG_MASK)) { 378 + *gfn = i; 379 + ret = true; 380 + break; 381 + } 382 + } 383 + return ret; 384 + } 385 + 352 386 static int kvmppc_memslot_page_merge(struct kvm *kvm, 353 387 const struct kvm_memory_slot *memslot, bool merge) 354 388 { ··· 494 458 495 459 srcu_read_unlock(&kvm->srcu, srcu_idx); 496 460 return ret; 497 - } 498 - 499 - unsigned long kvmppc_h_svm_init_done(struct kvm *kvm) 500 - { 501 - if (!(kvm->arch.secure_guest & KVMPPC_SECURE_INIT_START)) 502 - return H_UNSUPPORTED; 503 - 504 - kvm->arch.secure_guest |= KVMPPC_SECURE_INIT_DONE; 505 - pr_info("LPID %d went secure\n", kvm->arch.lpid); 506 - return H_SUCCESS; 507 461 } 508 462 509 463 /* ··· 614 588 } 615 589 616 590 /* 617 - * Alloc a PFN from private device memory pool and copy page from normal 618 - * memory to secure memory using UV_PAGE_IN uvcall. 591 + * Alloc a PFN from private device memory pool. If @pagein is true, 592 + * copy page from normal memory to secure memory using UV_PAGE_IN uvcall. 619 593 */ 620 - static int kvmppc_svm_page_in(struct vm_area_struct *vma, unsigned long start, 621 - unsigned long end, unsigned long gpa, struct kvm *kvm, 622 - unsigned long page_shift) 594 + static int kvmppc_svm_page_in(struct vm_area_struct *vma, 595 + unsigned long start, 596 + unsigned long end, unsigned long gpa, struct kvm *kvm, 597 + unsigned long page_shift, 598 + bool pagein) 623 599 { 624 600 unsigned long src_pfn, dst_pfn = 0; 625 601 struct migrate_vma mig; ··· 652 624 goto out_finalize; 653 625 } 654 626 655 - pfn = *mig.src >> MIGRATE_PFN_SHIFT; 656 - spage = migrate_pfn_to_page(*mig.src); 657 - if (spage) 658 - uv_page_in(kvm->arch.lpid, pfn << page_shift, gpa, 0, 659 - page_shift); 627 + if (pagein) { 628 + pfn = *mig.src >> MIGRATE_PFN_SHIFT; 629 + spage = migrate_pfn_to_page(*mig.src); 630 + if (spage) { 631 + ret = uv_page_in(kvm->arch.lpid, pfn << page_shift, 632 + gpa, 0, page_shift); 633 + if (ret) 634 + goto out_finalize; 635 + } 636 + } 660 637 661 638 *mig.dst = migrate_pfn(page_to_pfn(dpage)) | MIGRATE_PFN_LOCKED; 662 639 migrate_vma_pages(&mig); 663 640 out_finalize: 664 641 migrate_vma_finalize(&mig); 642 + return ret; 643 + } 644 + 645 + static int kvmppc_uv_migrate_mem_slot(struct kvm *kvm, 646 + const struct kvm_memory_slot *memslot) 647 + { 648 + unsigned long gfn = memslot->base_gfn; 649 + struct vm_area_struct *vma; 650 + unsigned long start, end; 651 + int ret = 0; 652 + 653 + mmap_read_lock(kvm->mm); 654 + mutex_lock(&kvm->arch.uvmem_lock); 655 + while (kvmppc_next_nontransitioned_gfn(memslot, kvm, &gfn)) { 656 + ret = H_STATE; 657 + start = gfn_to_hva(kvm, gfn); 658 + if (kvm_is_error_hva(start)) 659 + break; 660 + 661 + end = start + (1UL << PAGE_SHIFT); 662 + vma = find_vma_intersection(kvm->mm, start, end); 663 + if (!vma || vma->vm_start > start || vma->vm_end < end) 664 + break; 665 + 666 + ret = kvmppc_svm_page_in(vma, start, end, 667 + (gfn << PAGE_SHIFT), kvm, PAGE_SHIFT, false); 668 + if (ret) { 669 + ret = H_STATE; 670 + break; 671 + } 672 + 673 + /* relinquish the cpu if needed */ 674 + cond_resched(); 675 + } 676 + mutex_unlock(&kvm->arch.uvmem_lock); 677 + mmap_read_unlock(kvm->mm); 678 + return ret; 679 + } 680 + 681 + unsigned long kvmppc_h_svm_init_done(struct kvm *kvm) 682 + { 683 + struct kvm_memslots *slots; 684 + struct kvm_memory_slot *memslot; 685 + int srcu_idx; 686 + long ret = H_SUCCESS; 687 + 688 + if (!(kvm->arch.secure_guest & KVMPPC_SECURE_INIT_START)) 689 + return H_UNSUPPORTED; 690 + 691 + /* migrate any unmoved normal pfn to device pfns*/ 692 + srcu_idx = srcu_read_lock(&kvm->srcu); 693 + slots = kvm_memslots(kvm); 694 + kvm_for_each_memslot(memslot, slots) { 695 + ret = kvmppc_uv_migrate_mem_slot(kvm, memslot); 696 + if (ret) { 697 + /* 698 + * The pages will remain transitioned. 699 + * Its the callers responsibility to 700 + * terminate the VM, which will undo 701 + * all state of the VM. Till then 702 + * this VM is in a erroneous state. 703 + * Its KVMPPC_SECURE_INIT_DONE will 704 + * remain unset. 705 + */ 706 + ret = H_STATE; 707 + goto out; 708 + } 709 + } 710 + 711 + kvm->arch.secure_guest |= KVMPPC_SECURE_INIT_DONE; 712 + pr_info("LPID %d went secure\n", kvm->arch.lpid); 713 + 714 + out: 715 + srcu_read_unlock(&kvm->srcu, srcu_idx); 665 716 return ret; 666 717 } 667 718 ··· 852 745 if (!vma || vma->vm_start > start || vma->vm_end < end) 853 746 goto out_unlock; 854 747 855 - if (!kvmppc_svm_page_in(vma, start, end, gpa, kvm, page_shift)) 856 - ret = H_SUCCESS; 748 + if (kvmppc_svm_page_in(vma, start, end, gpa, kvm, page_shift, 749 + true)) 750 + goto out_unlock; 751 + 752 + ret = H_SUCCESS; 857 753 858 754 out_unlock: 859 755 mutex_unlock(&kvm->arch.uvmem_lock);