Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / drivers / xen / xlate_mmu.c
diff --git a/kernel/drivers/xen/xlate_mmu.c b/kernel/drivers/xen/xlate_mmu.c
new file mode 100644 (file)
index 0000000..58a5389
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * MMU operations common to all auto-translated physmap guests.
+ *
+ * Copyright (C) 2015 Citrix Systems R&D Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+#include <linux/kernel.h>
+#include <linux/mm.h>
+
+#include <asm/xen/hypercall.h>
+#include <asm/xen/hypervisor.h>
+
+#include <xen/xen.h>
+#include <xen/page.h>
+#include <xen/interface/xen.h>
+#include <xen/interface/memory.h>
+
+/* map fgmfn of domid to lpfn in the current domain */
+static int map_foreign_page(unsigned long lpfn, unsigned long fgmfn,
+                           unsigned int domid)
+{
+       int rc;
+       struct xen_add_to_physmap_range xatp = {
+               .domid = DOMID_SELF,
+               .foreign_domid = domid,
+               .size = 1,
+               .space = XENMAPSPACE_gmfn_foreign,
+       };
+       xen_ulong_t idx = fgmfn;
+       xen_pfn_t gpfn = lpfn;
+       int err = 0;
+
+       set_xen_guest_handle(xatp.idxs, &idx);
+       set_xen_guest_handle(xatp.gpfns, &gpfn);
+       set_xen_guest_handle(xatp.errs, &err);
+
+       rc = HYPERVISOR_memory_op(XENMEM_add_to_physmap_range, &xatp);
+       return rc < 0 ? rc : err;
+}
+
+struct remap_data {
+       xen_pfn_t *fgmfn; /* foreign domain's gmfn */
+       pgprot_t prot;
+       domid_t  domid;
+       struct vm_area_struct *vma;
+       int index;
+       struct page **pages;
+       struct xen_remap_mfn_info *info;
+       int *err_ptr;
+       int mapped;
+};
+
+static int remap_pte_fn(pte_t *ptep, pgtable_t token, unsigned long addr,
+                       void *data)
+{
+       struct remap_data *info = data;
+       struct page *page = info->pages[info->index++];
+       unsigned long pfn = page_to_pfn(page);
+       pte_t pte = pte_mkspecial(pfn_pte(pfn, info->prot));
+       int rc;
+
+       rc = map_foreign_page(pfn, *info->fgmfn, info->domid);
+       *info->err_ptr++ = rc;
+       if (!rc) {
+               set_pte_at(info->vma->vm_mm, addr, ptep, pte);
+               info->mapped++;
+       }
+       info->fgmfn++;
+
+       return 0;
+}
+
+int xen_xlate_remap_gfn_array(struct vm_area_struct *vma,
+                             unsigned long addr,
+                             xen_pfn_t *mfn, int nr,
+                             int *err_ptr, pgprot_t prot,
+                             unsigned domid,
+                             struct page **pages)
+{
+       int err;
+       struct remap_data data;
+       unsigned long range = nr << PAGE_SHIFT;
+
+       /* Kept here for the purpose of making sure code doesn't break
+          x86 PVOPS */
+       BUG_ON(!((vma->vm_flags & (VM_PFNMAP | VM_IO)) == (VM_PFNMAP | VM_IO)));
+
+       data.fgmfn = mfn;
+       data.prot  = prot;
+       data.domid = domid;
+       data.vma   = vma;
+       data.pages = pages;
+       data.index = 0;
+       data.err_ptr = err_ptr;
+       data.mapped = 0;
+
+       err = apply_to_page_range(vma->vm_mm, addr, range,
+                                 remap_pte_fn, &data);
+       return err < 0 ? err : data.mapped;
+}
+EXPORT_SYMBOL_GPL(xen_xlate_remap_gfn_array);
+
+int xen_xlate_unmap_gfn_range(struct vm_area_struct *vma,
+                             int nr, struct page **pages)
+{
+       int i;
+
+       for (i = 0; i < nr; i++) {
+               struct xen_remove_from_physmap xrp;
+               unsigned long pfn;
+
+               pfn = page_to_pfn(pages[i]);
+
+               xrp.domid = DOMID_SELF;
+               xrp.gpfn = pfn;
+               (void)HYPERVISOR_memory_op(XENMEM_remove_from_physmap, &xrp);
+       }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(xen_xlate_unmap_gfn_range);