diff options
author | Mukesh Rathor <mukesh.rathor@oracle.com> | 2014-05-23 22:33:44 -0400 |
---|---|---|
committer | David Vrabel <david.vrabel@citrix.com> | 2014-05-27 06:47:04 -0400 |
commit | 77945ca73e9a66cae25882fcab33ae0c6692763f (patch) | |
tree | 07c59a1c565d26245744c7930cafe69c6dae8ecd /arch/x86/xen | |
parent | 1a4b50f674d0d2f66569f08d063996971b7d48f2 (diff) |
x86/xen: map foreign pfns for autotranslated guests
When running as a dom0 in PVH mode, foreign pfns that are accessed
must be added to our p2m which is managed by xen. This is done via
XENMEM_add_to_physmap_range hypercall. This is needed for toolstack
building guests and mapping guest memory, xentrace mapping xen pages,
etc.
Signed-off-by: Mukesh Rathor <mukesh.rathor@oracle.com>
Signed-off-by: David Vrabel <david.vrabel@citrix.com>
Diffstat (limited to 'arch/x86/xen')
-rw-r--r-- | arch/x86/xen/mmu.c | 121 |
1 files changed, 118 insertions, 3 deletions
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c index d91602424b39..6f6e15d28466 100644 --- a/arch/x86/xen/mmu.c +++ b/arch/x86/xen/mmu.c | |||
@@ -2510,6 +2510,95 @@ void __init xen_hvm_init_mmu_ops(void) | |||
2510 | } | 2510 | } |
2511 | #endif | 2511 | #endif |
2512 | 2512 | ||
2513 | #ifdef CONFIG_XEN_PVH | ||
2514 | /* | ||
2515 | * Map foreign gfn (fgfn), to local pfn (lpfn). This for the user | ||
2516 | * space creating new guest on pvh dom0 and needing to map domU pages. | ||
2517 | */ | ||
2518 | static int xlate_add_to_p2m(unsigned long lpfn, unsigned long fgfn, | ||
2519 | unsigned int domid) | ||
2520 | { | ||
2521 | int rc, err = 0; | ||
2522 | xen_pfn_t gpfn = lpfn; | ||
2523 | xen_ulong_t idx = fgfn; | ||
2524 | |||
2525 | struct xen_add_to_physmap_range xatp = { | ||
2526 | .domid = DOMID_SELF, | ||
2527 | .foreign_domid = domid, | ||
2528 | .size = 1, | ||
2529 | .space = XENMAPSPACE_gmfn_foreign, | ||
2530 | }; | ||
2531 | set_xen_guest_handle(xatp.idxs, &idx); | ||
2532 | set_xen_guest_handle(xatp.gpfns, &gpfn); | ||
2533 | set_xen_guest_handle(xatp.errs, &err); | ||
2534 | |||
2535 | rc = HYPERVISOR_memory_op(XENMEM_add_to_physmap_range, &xatp); | ||
2536 | if (rc < 0) | ||
2537 | return rc; | ||
2538 | return err; | ||
2539 | } | ||
2540 | |||
2541 | static int xlate_remove_from_p2m(unsigned long spfn, int count) | ||
2542 | { | ||
2543 | struct xen_remove_from_physmap xrp; | ||
2544 | int i, rc; | ||
2545 | |||
2546 | for (i = 0; i < count; i++) { | ||
2547 | xrp.domid = DOMID_SELF; | ||
2548 | xrp.gpfn = spfn+i; | ||
2549 | rc = HYPERVISOR_memory_op(XENMEM_remove_from_physmap, &xrp); | ||
2550 | if (rc) | ||
2551 | break; | ||
2552 | } | ||
2553 | return rc; | ||
2554 | } | ||
2555 | |||
2556 | struct xlate_remap_data { | ||
2557 | unsigned long fgfn; /* foreign domain's gfn */ | ||
2558 | pgprot_t prot; | ||
2559 | domid_t domid; | ||
2560 | int index; | ||
2561 | struct page **pages; | ||
2562 | }; | ||
2563 | |||
2564 | static int xlate_map_pte_fn(pte_t *ptep, pgtable_t token, unsigned long addr, | ||
2565 | void *data) | ||
2566 | { | ||
2567 | int rc; | ||
2568 | struct xlate_remap_data *remap = data; | ||
2569 | unsigned long pfn = page_to_pfn(remap->pages[remap->index++]); | ||
2570 | pte_t pteval = pte_mkspecial(pfn_pte(pfn, remap->prot)); | ||
2571 | |||
2572 | rc = xlate_add_to_p2m(pfn, remap->fgfn, remap->domid); | ||
2573 | if (rc) | ||
2574 | return rc; | ||
2575 | native_set_pte(ptep, pteval); | ||
2576 | |||
2577 | return 0; | ||
2578 | } | ||
2579 | |||
2580 | static int xlate_remap_gfn_range(struct vm_area_struct *vma, | ||
2581 | unsigned long addr, unsigned long mfn, | ||
2582 | int nr, pgprot_t prot, unsigned domid, | ||
2583 | struct page **pages) | ||
2584 | { | ||
2585 | int err; | ||
2586 | struct xlate_remap_data pvhdata; | ||
2587 | |||
2588 | BUG_ON(!pages); | ||
2589 | |||
2590 | pvhdata.fgfn = mfn; | ||
2591 | pvhdata.prot = prot; | ||
2592 | pvhdata.domid = domid; | ||
2593 | pvhdata.index = 0; | ||
2594 | pvhdata.pages = pages; | ||
2595 | err = apply_to_page_range(vma->vm_mm, addr, nr << PAGE_SHIFT, | ||
2596 | xlate_map_pte_fn, &pvhdata); | ||
2597 | flush_tlb_all(); | ||
2598 | return err; | ||
2599 | } | ||
2600 | #endif | ||
2601 | |||
2513 | #define REMAP_BATCH_SIZE 16 | 2602 | #define REMAP_BATCH_SIZE 16 |
2514 | 2603 | ||
2515 | struct remap_data { | 2604 | struct remap_data { |
@@ -2544,11 +2633,18 @@ int xen_remap_domain_mfn_range(struct vm_area_struct *vma, | |||
2544 | unsigned long range; | 2633 | unsigned long range; |
2545 | int err = 0; | 2634 | int err = 0; |
2546 | 2635 | ||
2547 | if (xen_feature(XENFEAT_auto_translated_physmap)) | ||
2548 | return -EINVAL; | ||
2549 | |||
2550 | BUG_ON(!((vma->vm_flags & (VM_PFNMAP | VM_IO)) == (VM_PFNMAP | VM_IO))); | 2636 | BUG_ON(!((vma->vm_flags & (VM_PFNMAP | VM_IO)) == (VM_PFNMAP | VM_IO))); |
2551 | 2637 | ||
2638 | if (xen_feature(XENFEAT_auto_translated_physmap)) { | ||
2639 | #ifdef CONFIG_XEN_PVH | ||
2640 | /* We need to update the local page tables and the xen HAP */ | ||
2641 | return xlate_remap_gfn_range(vma, addr, mfn, nr, prot, | ||
2642 | domid, pages); | ||
2643 | #else | ||
2644 | return -EINVAL; | ||
2645 | #endif | ||
2646 | } | ||
2647 | |||
2552 | rmd.mfn = mfn; | 2648 | rmd.mfn = mfn; |
2553 | rmd.prot = prot; | 2649 | rmd.prot = prot; |
2554 | 2650 | ||
@@ -2586,6 +2682,25 @@ int xen_unmap_domain_mfn_range(struct vm_area_struct *vma, | |||
2586 | if (!pages || !xen_feature(XENFEAT_auto_translated_physmap)) | 2682 | if (!pages || !xen_feature(XENFEAT_auto_translated_physmap)) |
2587 | return 0; | 2683 | return 0; |
2588 | 2684 | ||
2685 | #ifdef CONFIG_XEN_PVH | ||
2686 | while (numpgs--) { | ||
2687 | /* | ||
2688 | * The mmu has already cleaned up the process mmu | ||
2689 | * resources at this point (lookup_address will return | ||
2690 | * NULL). | ||
2691 | */ | ||
2692 | unsigned long pfn = page_to_pfn(pages[numpgs]); | ||
2693 | |||
2694 | xlate_remove_from_p2m(pfn, 1); | ||
2695 | } | ||
2696 | /* | ||
2697 | * We don't need to flush tlbs because as part of | ||
2698 | * xlate_remove_from_p2m, the hypervisor will do tlb flushes | ||
2699 | * after removing the p2m entries from the EPT/NPT | ||
2700 | */ | ||
2701 | return 0; | ||
2702 | #else | ||
2589 | return -EINVAL; | 2703 | return -EINVAL; |
2704 | #endif | ||
2590 | } | 2705 | } |
2591 | EXPORT_SYMBOL_GPL(xen_unmap_domain_mfn_range); | 2706 | EXPORT_SYMBOL_GPL(xen_unmap_domain_mfn_range); |