summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/xen/enlighten.c11
-rw-r--r--arch/x86/xen/mmu.c60
-rw-r--r--drivers/xen/privcmd.c133
-rw-r--r--include/uapi/xen/privcmd.h11
-rw-r--r--include/xen/interface/memory.h66
-rw-r--r--include/xen/interface/xen.h7
-rw-r--r--include/xen/xen-ops.h24
7 files changed, 291 insertions, 21 deletions
diff --git a/arch/arm/xen/enlighten.c b/arch/arm/xen/enlighten.c
index ba7f4c8f5c3e..8073625371f5 100644
--- a/arch/arm/xen/enlighten.c
+++ b/arch/arm/xen/enlighten.c
@@ -89,6 +89,17 @@ int xen_unmap_domain_gfn_range(struct vm_area_struct *vma,
89} 89}
90EXPORT_SYMBOL_GPL(xen_unmap_domain_gfn_range); 90EXPORT_SYMBOL_GPL(xen_unmap_domain_gfn_range);
91 91
92/* Not used by XENFEAT_auto_translated guests. */
93int xen_remap_domain_mfn_array(struct vm_area_struct *vma,
94 unsigned long addr,
95 xen_pfn_t *mfn, int nr,
96 int *err_ptr, pgprot_t prot,
97 unsigned int domid, struct page **pages)
98{
99 return -ENOSYS;
100}
101EXPORT_SYMBOL_GPL(xen_remap_domain_mfn_array);
102
92static void xen_read_wallclock(struct timespec64 *ts) 103static void xen_read_wallclock(struct timespec64 *ts)
93{ 104{
94 u32 version; 105 u32 version;
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
index d33e7dbe3129..af2960cb7a3e 100644
--- a/arch/x86/xen/mmu.c
+++ b/arch/x86/xen/mmu.c
@@ -65,37 +65,44 @@ static void xen_flush_tlb_all(void)
65#define REMAP_BATCH_SIZE 16 65#define REMAP_BATCH_SIZE 16
66 66
67struct remap_data { 67struct remap_data {
68 xen_pfn_t *mfn; 68 xen_pfn_t *pfn;
69 bool contiguous; 69 bool contiguous;
70 bool no_translate;
70 pgprot_t prot; 71 pgprot_t prot;
71 struct mmu_update *mmu_update; 72 struct mmu_update *mmu_update;
72}; 73};
73 74
74static int remap_area_mfn_pte_fn(pte_t *ptep, pgtable_t token, 75static int remap_area_pfn_pte_fn(pte_t *ptep, pgtable_t token,
75 unsigned long addr, void *data) 76 unsigned long addr, void *data)
76{ 77{
77 struct remap_data *rmd = data; 78 struct remap_data *rmd = data;
78 pte_t pte = pte_mkspecial(mfn_pte(*rmd->mfn, rmd->prot)); 79 pte_t pte = pte_mkspecial(mfn_pte(*rmd->pfn, rmd->prot));
79 80
80 /* If we have a contiguous range, just update the mfn itself, 81 /*
81 else update pointer to be "next mfn". */ 82 * If we have a contiguous range, just update the pfn itself,
83 * else update pointer to be "next pfn".
84 */
82 if (rmd->contiguous) 85 if (rmd->contiguous)
83 (*rmd->mfn)++; 86 (*rmd->pfn)++;
84 else 87 else
85 rmd->mfn++; 88 rmd->pfn++;
86 89
87 rmd->mmu_update->ptr = virt_to_machine(ptep).maddr | MMU_NORMAL_PT_UPDATE; 90 rmd->mmu_update->ptr = virt_to_machine(ptep).maddr;
91 rmd->mmu_update->ptr |= rmd->no_translate ?
92 MMU_PT_UPDATE_NO_TRANSLATE :
93 MMU_NORMAL_PT_UPDATE;
88 rmd->mmu_update->val = pte_val_ma(pte); 94 rmd->mmu_update->val = pte_val_ma(pte);
89 rmd->mmu_update++; 95 rmd->mmu_update++;
90 96
91 return 0; 97 return 0;
92} 98}
93 99
94static int do_remap_gfn(struct vm_area_struct *vma, 100static int do_remap_pfn(struct vm_area_struct *vma,
95 unsigned long addr, 101 unsigned long addr,
96 xen_pfn_t *gfn, int nr, 102 xen_pfn_t *pfn, int nr,
97 int *err_ptr, pgprot_t prot, 103 int *err_ptr, pgprot_t prot,
98 unsigned domid, 104 unsigned int domid,
105 bool no_translate,
99 struct page **pages) 106 struct page **pages)
100{ 107{
101 int err = 0; 108 int err = 0;
@@ -106,11 +113,14 @@ static int do_remap_gfn(struct vm_area_struct *vma,
106 113
107 BUG_ON(!((vma->vm_flags & (VM_PFNMAP | VM_IO)) == (VM_PFNMAP | VM_IO))); 114 BUG_ON(!((vma->vm_flags & (VM_PFNMAP | VM_IO)) == (VM_PFNMAP | VM_IO)));
108 115
109 rmd.mfn = gfn; 116 rmd.pfn = pfn;
110 rmd.prot = prot; 117 rmd.prot = prot;
111 /* We use the err_ptr to indicate if there we are doing a contiguous 118 /*
112 * mapping or a discontigious mapping. */ 119 * We use the err_ptr to indicate if there we are doing a contiguous
120 * mapping or a discontigious mapping.
121 */
113 rmd.contiguous = !err_ptr; 122 rmd.contiguous = !err_ptr;
123 rmd.no_translate = no_translate;
114 124
115 while (nr) { 125 while (nr) {
116 int index = 0; 126 int index = 0;
@@ -121,7 +131,7 @@ static int do_remap_gfn(struct vm_area_struct *vma,
121 131
122 rmd.mmu_update = mmu_update; 132 rmd.mmu_update = mmu_update;
123 err = apply_to_page_range(vma->vm_mm, addr, range, 133 err = apply_to_page_range(vma->vm_mm, addr, range,
124 remap_area_mfn_pte_fn, &rmd); 134 remap_area_pfn_pte_fn, &rmd);
125 if (err) 135 if (err)
126 goto out; 136 goto out;
127 137
@@ -175,7 +185,8 @@ int xen_remap_domain_gfn_range(struct vm_area_struct *vma,
175 if (xen_feature(XENFEAT_auto_translated_physmap)) 185 if (xen_feature(XENFEAT_auto_translated_physmap))
176 return -EOPNOTSUPP; 186 return -EOPNOTSUPP;
177 187
178 return do_remap_gfn(vma, addr, &gfn, nr, NULL, prot, domid, pages); 188 return do_remap_pfn(vma, addr, &gfn, nr, NULL, prot, domid, false,
189 pages);
179} 190}
180EXPORT_SYMBOL_GPL(xen_remap_domain_gfn_range); 191EXPORT_SYMBOL_GPL(xen_remap_domain_gfn_range);
181 192
@@ -194,10 +205,25 @@ int xen_remap_domain_gfn_array(struct vm_area_struct *vma,
194 * cause of "wrong memory was mapped in". 205 * cause of "wrong memory was mapped in".
195 */ 206 */
196 BUG_ON(err_ptr == NULL); 207 BUG_ON(err_ptr == NULL);
197 return do_remap_gfn(vma, addr, gfn, nr, err_ptr, prot, domid, pages); 208 return do_remap_pfn(vma, addr, gfn, nr, err_ptr, prot, domid,
209 false, pages);
198} 210}
199EXPORT_SYMBOL_GPL(xen_remap_domain_gfn_array); 211EXPORT_SYMBOL_GPL(xen_remap_domain_gfn_array);
200 212
213int xen_remap_domain_mfn_array(struct vm_area_struct *vma,
214 unsigned long addr,
215 xen_pfn_t *mfn, int nr,
216 int *err_ptr, pgprot_t prot,
217 unsigned int domid, struct page **pages)
218{
219 if (xen_feature(XENFEAT_auto_translated_physmap))
220 return -EOPNOTSUPP;
221
222 return do_remap_pfn(vma, addr, mfn, nr, err_ptr, prot, domid,
223 true, pages);
224}
225EXPORT_SYMBOL_GPL(xen_remap_domain_mfn_array);
226
201/* Returns: 0 success */ 227/* Returns: 0 success */
202int xen_unmap_domain_gfn_range(struct vm_area_struct *vma, 228int xen_unmap_domain_gfn_range(struct vm_area_struct *vma,
203 int nr, struct page **pages) 229 int nr, struct page **pages)
diff --git a/drivers/xen/privcmd.c b/drivers/xen/privcmd.c
index 0a778d30d333..8ae0349d9f0a 100644
--- a/drivers/xen/privcmd.c
+++ b/drivers/xen/privcmd.c
@@ -33,6 +33,7 @@
33#include <xen/xen.h> 33#include <xen/xen.h>
34#include <xen/privcmd.h> 34#include <xen/privcmd.h>
35#include <xen/interface/xen.h> 35#include <xen/interface/xen.h>
36#include <xen/interface/memory.h>
36#include <xen/interface/hvm/dm_op.h> 37#include <xen/interface/hvm/dm_op.h>
37#include <xen/features.h> 38#include <xen/features.h>
38#include <xen/page.h> 39#include <xen/page.h>
@@ -722,6 +723,134 @@ static long privcmd_ioctl_restrict(struct file *file, void __user *udata)
722 return 0; 723 return 0;
723} 724}
724 725
726struct remap_pfn {
727 struct mm_struct *mm;
728 struct page **pages;
729 pgprot_t prot;
730 unsigned long i;
731};
732
733static int remap_pfn_fn(pte_t *ptep, pgtable_t token, unsigned long addr,
734 void *data)
735{
736 struct remap_pfn *r = data;
737 struct page *page = r->pages[r->i];
738 pte_t pte = pte_mkspecial(pfn_pte(page_to_pfn(page), r->prot));
739
740 set_pte_at(r->mm, addr, ptep, pte);
741 r->i++;
742
743 return 0;
744}
745
746static long privcmd_ioctl_mmap_resource(struct file *file, void __user *udata)
747{
748 struct privcmd_data *data = file->private_data;
749 struct mm_struct *mm = current->mm;
750 struct vm_area_struct *vma;
751 struct privcmd_mmap_resource kdata;
752 xen_pfn_t *pfns = NULL;
753 struct xen_mem_acquire_resource xdata;
754 int rc;
755
756 if (copy_from_user(&kdata, udata, sizeof(kdata)))
757 return -EFAULT;
758
759 /* If restriction is in place, check the domid matches */
760 if (data->domid != DOMID_INVALID && data->domid != kdata.dom)
761 return -EPERM;
762
763 down_write(&mm->mmap_sem);
764
765 vma = find_vma(mm, kdata.addr);
766 if (!vma || vma->vm_ops != &privcmd_vm_ops) {
767 rc = -EINVAL;
768 goto out;
769 }
770
771 pfns = kcalloc(kdata.num, sizeof(*pfns), GFP_KERNEL);
772 if (!pfns) {
773 rc = -ENOMEM;
774 goto out;
775 }
776
777 if (xen_feature(XENFEAT_auto_translated_physmap)) {
778 unsigned int nr = DIV_ROUND_UP(kdata.num, XEN_PFN_PER_PAGE);
779 struct page **pages;
780 unsigned int i;
781
782 rc = alloc_empty_pages(vma, nr);
783 if (rc < 0)
784 goto out;
785
786 pages = vma->vm_private_data;
787 for (i = 0; i < kdata.num; i++) {
788 xen_pfn_t pfn =
789 page_to_xen_pfn(pages[i / XEN_PFN_PER_PAGE]);
790
791 pfns[i] = pfn + (i % XEN_PFN_PER_PAGE);
792 }
793 } else
794 vma->vm_private_data = PRIV_VMA_LOCKED;
795
796 memset(&xdata, 0, sizeof(xdata));
797 xdata.domid = kdata.dom;
798 xdata.type = kdata.type;
799 xdata.id = kdata.id;
800 xdata.frame = kdata.idx;
801 xdata.nr_frames = kdata.num;
802 set_xen_guest_handle(xdata.frame_list, pfns);
803
804 xen_preemptible_hcall_begin();
805 rc = HYPERVISOR_memory_op(XENMEM_acquire_resource, &xdata);
806 xen_preemptible_hcall_end();
807
808 if (rc)
809 goto out;
810
811 if (xen_feature(XENFEAT_auto_translated_physmap)) {
812 struct remap_pfn r = {
813 .mm = vma->vm_mm,
814 .pages = vma->vm_private_data,
815 .prot = vma->vm_page_prot,
816 };
817
818 rc = apply_to_page_range(r.mm, kdata.addr,
819 kdata.num << PAGE_SHIFT,
820 remap_pfn_fn, &r);
821 } else {
822 unsigned int domid =
823 (xdata.flags & XENMEM_rsrc_acq_caller_owned) ?
824 DOMID_SELF : kdata.dom;
825 int num;
826
827 num = xen_remap_domain_mfn_array(vma,
828 kdata.addr & PAGE_MASK,
829 pfns, kdata.num, (int *)pfns,
830 vma->vm_page_prot,
831 domid,
832 vma->vm_private_data);
833 if (num < 0)
834 rc = num;
835 else if (num != kdata.num) {
836 unsigned int i;
837
838 for (i = 0; i < num; i++) {
839 rc = pfns[i];
840 if (rc < 0)
841 break;
842 }
843 } else
844 rc = 0;
845 }
846
847out:
848 up_write(&mm->mmap_sem);
849 kfree(pfns);
850
851 return rc;
852}
853
725static long privcmd_ioctl(struct file *file, 854static long privcmd_ioctl(struct file *file,
726 unsigned int cmd, unsigned long data) 855 unsigned int cmd, unsigned long data)
727{ 856{
@@ -753,6 +882,10 @@ static long privcmd_ioctl(struct file *file,
753 ret = privcmd_ioctl_restrict(file, udata); 882 ret = privcmd_ioctl_restrict(file, udata);
754 break; 883 break;
755 884
885 case IOCTL_PRIVCMD_MMAP_RESOURCE:
886 ret = privcmd_ioctl_mmap_resource(file, udata);
887 break;
888
756 default: 889 default:
757 break; 890 break;
758 } 891 }
diff --git a/include/uapi/xen/privcmd.h b/include/uapi/xen/privcmd.h
index 39d3e7b8e993..d2029556083e 100644
--- a/include/uapi/xen/privcmd.h
+++ b/include/uapi/xen/privcmd.h
@@ -89,6 +89,15 @@ struct privcmd_dm_op {
89 const struct privcmd_dm_op_buf __user *ubufs; 89 const struct privcmd_dm_op_buf __user *ubufs;
90}; 90};
91 91
92struct privcmd_mmap_resource {
93 domid_t dom;
94 __u32 type;
95 __u32 id;
96 __u32 idx;
97 __u64 num;
98 __u64 addr;
99};
100
92/* 101/*
93 * @cmd: IOCTL_PRIVCMD_HYPERCALL 102 * @cmd: IOCTL_PRIVCMD_HYPERCALL
94 * @arg: &privcmd_hypercall_t 103 * @arg: &privcmd_hypercall_t
@@ -114,5 +123,7 @@ struct privcmd_dm_op {
114 _IOC(_IOC_NONE, 'P', 5, sizeof(struct privcmd_dm_op)) 123 _IOC(_IOC_NONE, 'P', 5, sizeof(struct privcmd_dm_op))
115#define IOCTL_PRIVCMD_RESTRICT \ 124#define IOCTL_PRIVCMD_RESTRICT \
116 _IOC(_IOC_NONE, 'P', 6, sizeof(domid_t)) 125 _IOC(_IOC_NONE, 'P', 6, sizeof(domid_t))
126#define IOCTL_PRIVCMD_MMAP_RESOURCE \
127 _IOC(_IOC_NONE, 'P', 7, sizeof(struct privcmd_mmap_resource))
117 128
118#endif /* __LINUX_PUBLIC_PRIVCMD_H__ */ 129#endif /* __LINUX_PUBLIC_PRIVCMD_H__ */
diff --git a/include/xen/interface/memory.h b/include/xen/interface/memory.h
index 583dd93b3016..4c5751c26f87 100644
--- a/include/xen/interface/memory.h
+++ b/include/xen/interface/memory.h
@@ -265,4 +265,70 @@ struct xen_remove_from_physmap {
265}; 265};
266DEFINE_GUEST_HANDLE_STRUCT(xen_remove_from_physmap); 266DEFINE_GUEST_HANDLE_STRUCT(xen_remove_from_physmap);
267 267
268/*
269 * Get the pages for a particular guest resource, so that they can be
270 * mapped directly by a tools domain.
271 */
272#define XENMEM_acquire_resource 28
273struct xen_mem_acquire_resource {
274 /* IN - The domain whose resource is to be mapped */
275 domid_t domid;
276 /* IN - the type of resource */
277 uint16_t type;
278
279#define XENMEM_resource_ioreq_server 0
280#define XENMEM_resource_grant_table 1
281
282 /*
283 * IN - a type-specific resource identifier, which must be zero
284 * unless stated otherwise.
285 *
286 * type == XENMEM_resource_ioreq_server -> id == ioreq server id
287 * type == XENMEM_resource_grant_table -> id defined below
288 */
289 uint32_t id;
290
291#define XENMEM_resource_grant_table_id_shared 0
292#define XENMEM_resource_grant_table_id_status 1
293
294 /* IN/OUT - As an IN parameter number of frames of the resource
295 * to be mapped. However, if the specified value is 0 and
296 * frame_list is NULL then this field will be set to the
297 * maximum value supported by the implementation on return.
298 */
299 uint32_t nr_frames;
300 /*
301 * OUT - Must be zero on entry. On return this may contain a bitwise
302 * OR of the following values.
303 */
304 uint32_t flags;
305
306 /* The resource pages have been assigned to the calling domain */
307#define _XENMEM_rsrc_acq_caller_owned 0
308#define XENMEM_rsrc_acq_caller_owned (1u << _XENMEM_rsrc_acq_caller_owned)
309
310 /*
311 * IN - the index of the initial frame to be mapped. This parameter
312 * is ignored if nr_frames is 0.
313 */
314 uint64_t frame;
315
316#define XENMEM_resource_ioreq_server_frame_bufioreq 0
317#define XENMEM_resource_ioreq_server_frame_ioreq(n) (1 + (n))
318
319 /*
320 * IN/OUT - If the tools domain is PV then, upon return, frame_list
321 * will be populated with the MFNs of the resource.
322 * If the tools domain is HVM then it is expected that, on
323 * entry, frame_list will be populated with a list of GFNs
324 * that will be mapped to the MFNs of the resource.
325 * If -EIO is returned then the frame_list has only been
326 * partially mapped and it is up to the caller to unmap all
327 * the GFNs.
328 * This parameter may be NULL if nr_frames is 0.
329 */
330 GUEST_HANDLE(xen_pfn_t) frame_list;
331};
332DEFINE_GUEST_HANDLE_STRUCT(xen_mem_acquire_resource);
333
268#endif /* __XEN_PUBLIC_MEMORY_H__ */ 334#endif /* __XEN_PUBLIC_MEMORY_H__ */
diff --git a/include/xen/interface/xen.h b/include/xen/interface/xen.h
index 4f4830ef8f93..8bfb242f433e 100644
--- a/include/xen/interface/xen.h
+++ b/include/xen/interface/xen.h
@@ -265,9 +265,10 @@
265 * 265 *
266 * PAT (bit 7 on) --> PWT (bit 3 on) and clear bit 7. 266 * PAT (bit 7 on) --> PWT (bit 3 on) and clear bit 7.
267 */ 267 */
268#define MMU_NORMAL_PT_UPDATE 0 /* checked '*ptr = val'. ptr is MA. */ 268#define MMU_NORMAL_PT_UPDATE 0 /* checked '*ptr = val'. ptr is MA. */
269#define MMU_MACHPHYS_UPDATE 1 /* ptr = MA of frame to modify entry for */ 269#define MMU_MACHPHYS_UPDATE 1 /* ptr = MA of frame to modify entry for */
270#define MMU_PT_UPDATE_PRESERVE_AD 2 /* atomically: *ptr = val | (*ptr&(A|D)) */ 270#define MMU_PT_UPDATE_PRESERVE_AD 2 /* atomically: *ptr = val | (*ptr&(A|D)) */
271#define MMU_PT_UPDATE_NO_TRANSLATE 3 /* checked '*ptr = val'. ptr is MA. */
271 272
272/* 273/*
273 * MMU EXTENDED OPERATIONS 274 * MMU EXTENDED OPERATIONS
diff --git a/include/xen/xen-ops.h b/include/xen/xen-ops.h
index fd23e42c6024..fd18c974a619 100644
--- a/include/xen/xen-ops.h
+++ b/include/xen/xen-ops.h
@@ -63,7 +63,7 @@ static inline void xen_destroy_contiguous_region(phys_addr_t pstart,
63struct vm_area_struct; 63struct vm_area_struct;
64 64
65/* 65/*
66 * xen_remap_domain_gfn_array() - map an array of foreign frames 66 * xen_remap_domain_gfn_array() - map an array of foreign frames by gfn
67 * @vma: VMA to map the pages into 67 * @vma: VMA to map the pages into
68 * @addr: Address at which to map the pages 68 * @addr: Address at which to map the pages
69 * @gfn: Array of GFNs to map 69 * @gfn: Array of GFNs to map
@@ -86,6 +86,28 @@ int xen_remap_domain_gfn_array(struct vm_area_struct *vma,
86 unsigned domid, 86 unsigned domid,
87 struct page **pages); 87 struct page **pages);
88 88
89/*
90 * xen_remap_domain_mfn_array() - map an array of foreign frames by mfn
91 * @vma: VMA to map the pages into
92 * @addr: Address at which to map the pages
93 * @mfn: Array of MFNs to map
94 * @nr: Number entries in the MFN array
95 * @err_ptr: Returns per-MFN error status.
96 * @prot: page protection mask
97 * @domid: Domain owning the pages
98 * @pages: Array of pages if this domain has an auto-translated physmap
99 *
100 * @mfn and @err_ptr may point to the same buffer, the MFNs will be
101 * overwritten by the error codes after they are mapped.
102 *
103 * Returns the number of successfully mapped frames, or a -ve error
104 * code.
105 */
106int xen_remap_domain_mfn_array(struct vm_area_struct *vma,
107 unsigned long addr, xen_pfn_t *mfn, int nr,
108 int *err_ptr, pgprot_t prot,
109 unsigned int domid, struct page **pages);
110
89/* xen_remap_domain_gfn_range() - map a range of foreign frames 111/* xen_remap_domain_gfn_range() - map a range of foreign frames
90 * @vma: VMA to map the pages into 112 * @vma: VMA to map the pages into
91 * @addr: Address at which to map the pages 113 * @addr: Address at which to map the pages