1 /* 2 * MMU operations common to all auto-translated physmap guests. 3 * 4 * Copyright (C) 2015 Citrix Systems R&D Ltd. 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License version 2 8 * as published by the Free Software Foundation; or, when distributed 9 * separately from the Linux kernel or incorporated into other 10 * software packages, subject to the following license: 11 * 12 * Permission is hereby granted, free of charge, to any person obtaining a copy 13 * of this source file (the "Software"), to deal in the Software without 14 * restriction, including without limitation the rights to use, copy, modify, 15 * merge, publish, distribute, sublicense, and/or sell copies of the Software, 16 * and to permit persons to whom the Software is furnished to do so, subject to 17 * the following conditions: 18 * 19 * The above copyright notice and this permission notice shall be included in 20 * all copies or substantial portions of the Software. 21 * 22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 28 * IN THE SOFTWARE. 29 */ 30 #include <linux/kernel.h> 31 #include <linux/mm.h> 32 33 #include <asm/xen/hypercall.h> 34 #include <asm/xen/hypervisor.h> 35 36 #include <xen/xen.h> 37 #include <xen/page.h> 38 #include <xen/interface/xen.h> 39 #include <xen/interface/memory.h> 40 41 /* map fgmfn of domid to lpfn in the current domain */ 42 static int map_foreign_page(unsigned long lpfn, unsigned long fgmfn, 43 unsigned int domid) 44 { 45 int rc; 46 struct xen_add_to_physmap_range xatp = { 47 .domid = DOMID_SELF, 48 .foreign_domid = domid, 49 .size = 1, 50 .space = XENMAPSPACE_gmfn_foreign, 51 }; 52 xen_ulong_t idx = fgmfn; 53 xen_pfn_t gpfn = lpfn; 54 int err = 0; 55 56 set_xen_guest_handle(xatp.idxs, &idx); 57 set_xen_guest_handle(xatp.gpfns, &gpfn); 58 set_xen_guest_handle(xatp.errs, &err); 59 60 rc = HYPERVISOR_memory_op(XENMEM_add_to_physmap_range, &xatp); 61 return rc < 0 ? rc : err; 62 } 63 64 struct remap_data { 65 xen_pfn_t *fgmfn; /* foreign domain's gmfn */ 66 pgprot_t prot; 67 domid_t domid; 68 struct vm_area_struct *vma; 69 int index; 70 struct page **pages; 71 struct xen_remap_mfn_info *info; 72 int *err_ptr; 73 int mapped; 74 }; 75 76 static int remap_pte_fn(pte_t *ptep, pgtable_t token, unsigned long addr, 77 void *data) 78 { 79 struct remap_data *info = data; 80 struct page *page = info->pages[info->index++]; 81 unsigned long pfn = page_to_pfn(page); 82 pte_t pte = pte_mkspecial(pfn_pte(pfn, info->prot)); 83 int rc; 84 85 rc = map_foreign_page(pfn, *info->fgmfn, info->domid); 86 *info->err_ptr++ = rc; 87 if (!rc) { 88 set_pte_at(info->vma->vm_mm, addr, ptep, pte); 89 info->mapped++; 90 } 91 info->fgmfn++; 92 93 return 0; 94 } 95 96 int xen_xlate_remap_gfn_array(struct vm_area_struct *vma, 97 unsigned long addr, 98 xen_pfn_t *mfn, int nr, 99 int *err_ptr, pgprot_t prot, 100 unsigned domid, 101 struct page **pages) 102 { 103 int err; 104 struct remap_data data; 105 unsigned long range = nr << PAGE_SHIFT; 106 107 /* Kept here for the purpose of making sure code doesn't break 108 x86 PVOPS */ 109 BUG_ON(!((vma->vm_flags & (VM_PFNMAP | VM_IO)) == (VM_PFNMAP | VM_IO))); 110 111 data.fgmfn = mfn; 112 data.prot = prot; 113 data.domid = domid; 114 data.vma = vma; 115 data.pages = pages; 116 data.index = 0; 117 data.err_ptr = err_ptr; 118 data.mapped = 0; 119 120 err = apply_to_page_range(vma->vm_mm, addr, range, 121 remap_pte_fn, &data); 122 return err < 0 ? err : data.mapped; 123 } 124 EXPORT_SYMBOL_GPL(xen_xlate_remap_gfn_array); 125 126 int xen_xlate_unmap_gfn_range(struct vm_area_struct *vma, 127 int nr, struct page **pages) 128 { 129 int i; 130 131 for (i = 0; i < nr; i++) { 132 struct xen_remove_from_physmap xrp; 133 unsigned long pfn; 134 135 pfn = page_to_pfn(pages[i]); 136 137 xrp.domid = DOMID_SELF; 138 xrp.gpfn = pfn; 139 (void)HYPERVISOR_memory_op(XENMEM_remove_from_physmap, &xrp); 140 } 141 return 0; 142 } 143 EXPORT_SYMBOL_GPL(xen_xlate_unmap_gfn_range); 144