1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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
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;
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
108
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