aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/xen
diff options
context:
space:
mode:
authorMukesh Rathor <mukesh.rathor@oracle.com>2014-05-23 22:33:44 -0400
committerDavid Vrabel <david.vrabel@citrix.com>2014-05-27 06:47:04 -0400
commit77945ca73e9a66cae25882fcab33ae0c6692763f (patch)
tree07c59a1c565d26245744c7930cafe69c6dae8ecd /arch/x86/xen
parent1a4b50f674d0d2f66569f08d063996971b7d48f2 (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.c121
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 */
2518static 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
2541static 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
2556struct 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
2564static 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
2580static 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
2515struct remap_data { 2604struct 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}
2591EXPORT_SYMBOL_GPL(xen_unmap_domain_mfn_range); 2706EXPORT_SYMBOL_GPL(xen_unmap_domain_mfn_range);