Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  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
 41typedef void (*xen_gfn_fn_t)(unsigned long gfn, void *data);
 42
 43/* Break down the pages in 4KB chunk and call fn for each gfn */
 44static void xen_for_each_gfn(struct page **pages, unsigned nr_gfn,
 45			     xen_gfn_fn_t fn, void *data)
 46{
 47	unsigned long xen_pfn = 0;
 48	struct page *page;
 49	int i;
 50
 51	for (i = 0; i < nr_gfn; i++) {
 52		if ((i % XEN_PFN_PER_PAGE) == 0) {
 53			page = pages[i / XEN_PFN_PER_PAGE];
 54			xen_pfn = page_to_xen_pfn(page);
 55		}
 56		fn(pfn_to_gfn(xen_pfn++), data);
 57	}
 58}
 59
 60struct remap_data {
 61	xen_pfn_t *fgfn; /* foreign domain's gfn */
 62	int nr_fgfn; /* Number of foreign gfn left to map */
 63	pgprot_t prot;
 64	domid_t  domid;
 65	struct vm_area_struct *vma;
 66	int index;
 67	struct page **pages;
 68	struct xen_remap_gfn_info *info;
 69	int *err_ptr;
 70	int mapped;
 71
 72	/* Hypercall parameters */
 73	int h_errs[XEN_PFN_PER_PAGE];
 74	xen_ulong_t h_idxs[XEN_PFN_PER_PAGE];
 75	xen_pfn_t h_gpfns[XEN_PFN_PER_PAGE];
 76
 77	int h_iter;	/* Iterator */
 78};
 79
 80static void setup_hparams(unsigned long gfn, void *data)
 81{
 82	struct remap_data *info = data;
 83
 84	info->h_idxs[info->h_iter] = *info->fgfn;
 85	info->h_gpfns[info->h_iter] = gfn;
 86	info->h_errs[info->h_iter] = 0;
 87
 88	info->h_iter++;
 89	info->fgfn++;
 90}
 91
 92static int remap_pte_fn(pte_t *ptep, pgtable_t token, unsigned long addr,
 93			void *data)
 94{
 95	struct remap_data *info = data;
 96	struct page *page = info->pages[info->index++];
 97	pte_t pte = pte_mkspecial(pfn_pte(page_to_pfn(page), info->prot));
 98	int rc, nr_gfn;
 99	uint32_t i;
100	struct xen_add_to_physmap_range xatp = {
101		.domid = DOMID_SELF,
102		.foreign_domid = info->domid,
103		.space = XENMAPSPACE_gmfn_foreign,
104	};
105
106	nr_gfn = min_t(typeof(info->nr_fgfn), XEN_PFN_PER_PAGE, info->nr_fgfn);
107	info->nr_fgfn -= nr_gfn;
108
109	info->h_iter = 0;
110	xen_for_each_gfn(&page, nr_gfn, setup_hparams, info);
111	BUG_ON(info->h_iter != nr_gfn);
112
113	set_xen_guest_handle(xatp.idxs, info->h_idxs);
114	set_xen_guest_handle(xatp.gpfns, info->h_gpfns);
115	set_xen_guest_handle(xatp.errs, info->h_errs);
116	xatp.size = nr_gfn;
117
118	rc = HYPERVISOR_memory_op(XENMEM_add_to_physmap_range, &xatp);
119
120	/* info->err_ptr expect to have one error status per Xen PFN */
121	for (i = 0; i < nr_gfn; i++) {
122		int err = (rc < 0) ? rc : info->h_errs[i];
123
124		*(info->err_ptr++) = err;
125		if (!err)
126			info->mapped++;
127	}
128
129	/*
130	 * Note: The hypercall will return 0 in most of the case if even if
131	 * all the fgmfn are not mapped. We still have to update the pte
132	 * as the userspace may decide to continue.
133	 */
134	if (!rc)
135		set_pte_at(info->vma->vm_mm, addr, ptep, pte);
136
137	return 0;
138}
139
140int xen_xlate_remap_gfn_array(struct vm_area_struct *vma,
141			      unsigned long addr,
142			      xen_pfn_t *gfn, int nr,
143			      int *err_ptr, pgprot_t prot,
144			      unsigned domid,
145			      struct page **pages)
146{
147	int err;
148	struct remap_data data;
149	unsigned long range = DIV_ROUND_UP(nr, XEN_PFN_PER_PAGE) << PAGE_SHIFT;
150
151	/* Kept here for the purpose of making sure code doesn't break
152	   x86 PVOPS */
153	BUG_ON(!((vma->vm_flags & (VM_PFNMAP | VM_IO)) == (VM_PFNMAP | VM_IO)));
154
155	data.fgfn = gfn;
156	data.nr_fgfn = nr;
157	data.prot  = prot;
158	data.domid = domid;
159	data.vma   = vma;
160	data.pages = pages;
161	data.index = 0;
162	data.err_ptr = err_ptr;
163	data.mapped = 0;
164
165	err = apply_to_page_range(vma->vm_mm, addr, range,
166				  remap_pte_fn, &data);
167	return err < 0 ? err : data.mapped;
168}
169EXPORT_SYMBOL_GPL(xen_xlate_remap_gfn_array);
170
171static void unmap_gfn(unsigned long gfn, void *data)
172{
173	struct xen_remove_from_physmap xrp;
174
175	xrp.domid = DOMID_SELF;
176	xrp.gpfn = gfn;
177	(void)HYPERVISOR_memory_op(XENMEM_remove_from_physmap, &xrp);
178}
179
180int xen_xlate_unmap_gfn_range(struct vm_area_struct *vma,
181			      int nr, struct page **pages)
182{
183	xen_for_each_gfn(pages, nr, unmap_gfn, NULL);
184
185	return 0;
186}
187EXPORT_SYMBOL_GPL(xen_xlate_unmap_gfn_range);