linux/drivers/xen/xlate_mmu.c
<<
>>
Prefs
   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 fgfn of domid to lpfn in the current domain */
  42static int map_foreign_page(unsigned long lpfn, unsigned long fgfn,
  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 = fgfn;
  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
  64struct remap_data {
  65        xen_pfn_t *fgfn; /* foreign domain's gfn */
  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_gfn_info *info;
  72        int *err_ptr;
  73        int mapped;
  74};
  75
  76static 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->fgfn, 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->fgfn++;
  92
  93        return 0;
  94}
  95
  96int xen_xlate_remap_gfn_array(struct vm_area_struct *vma,
  97                              unsigned long addr,
  98                              xen_pfn_t *gfn, 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.fgfn = gfn;
 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}
 124EXPORT_SYMBOL_GPL(xen_xlate_remap_gfn_array);
 125
 126int 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}
 143EXPORT_SYMBOL_GPL(xen_xlate_unmap_gfn_range);
 144