xref: /freebsd/sys/dev/xen/privcmd/privcmd.c (revision bf7313e3b79a97459a499380221cde238271b028)
1*bf7313e3SRoger Pau Monné /*
2*bf7313e3SRoger Pau Monné  * Copyright (c) 2014 Roger Pau Monné <roger.pau@citrix.com>
3*bf7313e3SRoger Pau Monné  * All rights reserved.
4*bf7313e3SRoger Pau Monné  *
5*bf7313e3SRoger Pau Monné  * Redistribution and use in source and binary forms, with or without
6*bf7313e3SRoger Pau Monné  * modification, are permitted provided that the following conditions
7*bf7313e3SRoger Pau Monné  * are met:
8*bf7313e3SRoger Pau Monné  * 1. Redistributions of source code must retain the above copyright
9*bf7313e3SRoger Pau Monné  *    notice, this list of conditions and the following disclaimer.
10*bf7313e3SRoger Pau Monné  * 2. Redistributions in binary form must reproduce the above copyright
11*bf7313e3SRoger Pau Monné  *    notice, this list of conditions and the following disclaimer in the
12*bf7313e3SRoger Pau Monné  *    documentation and/or other materials provided with the distribution.
13*bf7313e3SRoger Pau Monné  *
14*bf7313e3SRoger Pau Monné  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS AS IS'' AND
15*bf7313e3SRoger Pau Monné  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16*bf7313e3SRoger Pau Monné  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17*bf7313e3SRoger Pau Monné  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18*bf7313e3SRoger Pau Monné  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19*bf7313e3SRoger Pau Monné  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20*bf7313e3SRoger Pau Monné  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21*bf7313e3SRoger Pau Monné  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22*bf7313e3SRoger Pau Monné  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23*bf7313e3SRoger Pau Monné  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24*bf7313e3SRoger Pau Monné  * SUCH DAMAGE.
25*bf7313e3SRoger Pau Monné  */
26*bf7313e3SRoger Pau Monné 
27*bf7313e3SRoger Pau Monné #include <sys/cdefs.h>
28*bf7313e3SRoger Pau Monné __FBSDID("$FreeBSD$");
29*bf7313e3SRoger Pau Monné 
30*bf7313e3SRoger Pau Monné #include <sys/param.h>
31*bf7313e3SRoger Pau Monné #include <sys/systm.h>
32*bf7313e3SRoger Pau Monné #include <sys/uio.h>
33*bf7313e3SRoger Pau Monné #include <sys/bus.h>
34*bf7313e3SRoger Pau Monné #include <sys/malloc.h>
35*bf7313e3SRoger Pau Monné #include <sys/kernel.h>
36*bf7313e3SRoger Pau Monné #include <sys/lock.h>
37*bf7313e3SRoger Pau Monné #include <sys/mutex.h>
38*bf7313e3SRoger Pau Monné #include <sys/rwlock.h>
39*bf7313e3SRoger Pau Monné #include <sys/selinfo.h>
40*bf7313e3SRoger Pau Monné #include <sys/poll.h>
41*bf7313e3SRoger Pau Monné #include <sys/conf.h>
42*bf7313e3SRoger Pau Monné #include <sys/fcntl.h>
43*bf7313e3SRoger Pau Monné #include <sys/ioccom.h>
44*bf7313e3SRoger Pau Monné #include <sys/rman.h>
45*bf7313e3SRoger Pau Monné #include <sys/tree.h>
46*bf7313e3SRoger Pau Monné #include <sys/module.h>
47*bf7313e3SRoger Pau Monné #include <sys/proc.h>
48*bf7313e3SRoger Pau Monné 
49*bf7313e3SRoger Pau Monné #include <vm/vm.h>
50*bf7313e3SRoger Pau Monné #include <vm/vm_param.h>
51*bf7313e3SRoger Pau Monné #include <vm/vm_extern.h>
52*bf7313e3SRoger Pau Monné #include <vm/vm_kern.h>
53*bf7313e3SRoger Pau Monné #include <vm/vm_page.h>
54*bf7313e3SRoger Pau Monné #include <vm/vm_map.h>
55*bf7313e3SRoger Pau Monné #include <vm/vm_object.h>
56*bf7313e3SRoger Pau Monné #include <vm/vm_pager.h>
57*bf7313e3SRoger Pau Monné #include <vm/vm_phys.h>
58*bf7313e3SRoger Pau Monné 
59*bf7313e3SRoger Pau Monné #include <machine/md_var.h>
60*bf7313e3SRoger Pau Monné 
61*bf7313e3SRoger Pau Monné #include <xen/xen-os.h>
62*bf7313e3SRoger Pau Monné #include <xen/hypervisor.h>
63*bf7313e3SRoger Pau Monné #include <xen/privcmd.h>
64*bf7313e3SRoger Pau Monné #include <xen/error.h>
65*bf7313e3SRoger Pau Monné 
66*bf7313e3SRoger Pau Monné MALLOC_DEFINE(M_PRIVCMD, "privcmd_dev", "Xen privcmd user-space device");
67*bf7313e3SRoger Pau Monné 
68*bf7313e3SRoger Pau Monné struct privcmd_map {
69*bf7313e3SRoger Pau Monné 	vm_object_t mem;
70*bf7313e3SRoger Pau Monné 	vm_size_t size;
71*bf7313e3SRoger Pau Monné 	struct resource *pseudo_phys_res;
72*bf7313e3SRoger Pau Monné 	int pseudo_phys_res_id;
73*bf7313e3SRoger Pau Monné 	vm_paddr_t phys_base_addr;
74*bf7313e3SRoger Pau Monné 	boolean_t mapped;
75*bf7313e3SRoger Pau Monné 	int *errs;
76*bf7313e3SRoger Pau Monné };
77*bf7313e3SRoger Pau Monné 
78*bf7313e3SRoger Pau Monné static d_ioctl_t     privcmd_ioctl;
79*bf7313e3SRoger Pau Monné static d_mmap_single_t	privcmd_mmap_single;
80*bf7313e3SRoger Pau Monné 
81*bf7313e3SRoger Pau Monné static struct cdevsw privcmd_devsw = {
82*bf7313e3SRoger Pau Monné 	.d_version = D_VERSION,
83*bf7313e3SRoger Pau Monné 	.d_ioctl = privcmd_ioctl,
84*bf7313e3SRoger Pau Monné 	.d_mmap_single = privcmd_mmap_single,
85*bf7313e3SRoger Pau Monné 	.d_name = "privcmd",
86*bf7313e3SRoger Pau Monné };
87*bf7313e3SRoger Pau Monné 
88*bf7313e3SRoger Pau Monné static int privcmd_pg_ctor(void *handle, vm_ooffset_t size, vm_prot_t prot,
89*bf7313e3SRoger Pau Monné     vm_ooffset_t foff, struct ucred *cred, u_short *color);
90*bf7313e3SRoger Pau Monné static void privcmd_pg_dtor(void *handle);
91*bf7313e3SRoger Pau Monné static int privcmd_pg_fault(vm_object_t object, vm_ooffset_t offset,
92*bf7313e3SRoger Pau Monné     int prot, vm_page_t *mres);
93*bf7313e3SRoger Pau Monné 
94*bf7313e3SRoger Pau Monné static struct cdev_pager_ops privcmd_pg_ops = {
95*bf7313e3SRoger Pau Monné 	.cdev_pg_fault = privcmd_pg_fault,
96*bf7313e3SRoger Pau Monné 	.cdev_pg_ctor =	privcmd_pg_ctor,
97*bf7313e3SRoger Pau Monné 	.cdev_pg_dtor =	privcmd_pg_dtor,
98*bf7313e3SRoger Pau Monné };
99*bf7313e3SRoger Pau Monné 
100*bf7313e3SRoger Pau Monné static device_t privcmd_dev = NULL;
101*bf7313e3SRoger Pau Monné 
102*bf7313e3SRoger Pau Monné /*------------------------- Privcmd Pager functions --------------------------*/
103*bf7313e3SRoger Pau Monné static int
104*bf7313e3SRoger Pau Monné privcmd_pg_ctor(void *handle, vm_ooffset_t size, vm_prot_t prot,
105*bf7313e3SRoger Pau Monné     vm_ooffset_t foff, struct ucred *cred, u_short *color)
106*bf7313e3SRoger Pau Monné {
107*bf7313e3SRoger Pau Monné 
108*bf7313e3SRoger Pau Monné 	return (0);
109*bf7313e3SRoger Pau Monné }
110*bf7313e3SRoger Pau Monné 
111*bf7313e3SRoger Pau Monné static void
112*bf7313e3SRoger Pau Monné privcmd_pg_dtor(void *handle)
113*bf7313e3SRoger Pau Monné {
114*bf7313e3SRoger Pau Monné 	struct xen_remove_from_physmap rm = { .domid = DOMID_SELF };
115*bf7313e3SRoger Pau Monné 	struct privcmd_map *map = handle;
116*bf7313e3SRoger Pau Monné 	int error;
117*bf7313e3SRoger Pau Monné 	vm_size_t i;
118*bf7313e3SRoger Pau Monné 	vm_page_t m;
119*bf7313e3SRoger Pau Monné 
120*bf7313e3SRoger Pau Monné 	/*
121*bf7313e3SRoger Pau Monné 	 * Remove the mappings from the used pages. This will remove the
122*bf7313e3SRoger Pau Monné 	 * underlying p2m bindings in Xen second stage translation.
123*bf7313e3SRoger Pau Monné 	 */
124*bf7313e3SRoger Pau Monné 	if (map->mapped == true) {
125*bf7313e3SRoger Pau Monné 		VM_OBJECT_WLOCK(map->mem);
126*bf7313e3SRoger Pau Monné retry:
127*bf7313e3SRoger Pau Monné 		for (i = 0; i < map->size; i++) {
128*bf7313e3SRoger Pau Monné 			m = vm_page_lookup(map->mem, i);
129*bf7313e3SRoger Pau Monné 			if (m == NULL)
130*bf7313e3SRoger Pau Monné 				continue;
131*bf7313e3SRoger Pau Monné 			if (vm_page_sleep_if_busy(m, "pcmdum"))
132*bf7313e3SRoger Pau Monné 				goto retry;
133*bf7313e3SRoger Pau Monné 			cdev_pager_free_page(map->mem, m);
134*bf7313e3SRoger Pau Monné 		}
135*bf7313e3SRoger Pau Monné 		VM_OBJECT_WUNLOCK(map->mem);
136*bf7313e3SRoger Pau Monné 
137*bf7313e3SRoger Pau Monné 		for (i = 0; i < map->size; i++) {
138*bf7313e3SRoger Pau Monné 			rm.gpfn = atop(map->phys_base_addr) + i;
139*bf7313e3SRoger Pau Monné 			HYPERVISOR_memory_op(XENMEM_remove_from_physmap, &rm);
140*bf7313e3SRoger Pau Monné 		}
141*bf7313e3SRoger Pau Monné 		free(map->errs, M_PRIVCMD);
142*bf7313e3SRoger Pau Monné 	}
143*bf7313e3SRoger Pau Monné 
144*bf7313e3SRoger Pau Monné 	vm_phys_fictitious_unreg_range(map->phys_base_addr,
145*bf7313e3SRoger Pau Monné 	    map->phys_base_addr + map->size * PAGE_SIZE);
146*bf7313e3SRoger Pau Monné 
147*bf7313e3SRoger Pau Monné 	error = bus_release_resource(privcmd_dev, SYS_RES_MEMORY,
148*bf7313e3SRoger Pau Monné 	    map->pseudo_phys_res_id, map->pseudo_phys_res);
149*bf7313e3SRoger Pau Monné 	KASSERT(error == 0, ("Unable to release memory resource: %d", error));
150*bf7313e3SRoger Pau Monné 
151*bf7313e3SRoger Pau Monné 	free(map, M_PRIVCMD);
152*bf7313e3SRoger Pau Monné }
153*bf7313e3SRoger Pau Monné 
154*bf7313e3SRoger Pau Monné static int
155*bf7313e3SRoger Pau Monné privcmd_pg_fault(vm_object_t object, vm_ooffset_t offset,
156*bf7313e3SRoger Pau Monné     int prot, vm_page_t *mres)
157*bf7313e3SRoger Pau Monné {
158*bf7313e3SRoger Pau Monné 	struct privcmd_map *map = object->handle;
159*bf7313e3SRoger Pau Monné 	vm_pindex_t pidx;
160*bf7313e3SRoger Pau Monné 	vm_page_t page, oldm;
161*bf7313e3SRoger Pau Monné 
162*bf7313e3SRoger Pau Monné 	if (map->mapped != true)
163*bf7313e3SRoger Pau Monné 		return (VM_PAGER_FAIL);
164*bf7313e3SRoger Pau Monné 
165*bf7313e3SRoger Pau Monné 	pidx = OFF_TO_IDX(offset);
166*bf7313e3SRoger Pau Monné 	if (pidx >= map->size || map->errs[pidx] != 0)
167*bf7313e3SRoger Pau Monné 		return (VM_PAGER_FAIL);
168*bf7313e3SRoger Pau Monné 
169*bf7313e3SRoger Pau Monné 	page = PHYS_TO_VM_PAGE(map->phys_base_addr + offset);
170*bf7313e3SRoger Pau Monné 	if (page == NULL)
171*bf7313e3SRoger Pau Monné 		return (VM_PAGER_FAIL);
172*bf7313e3SRoger Pau Monné 
173*bf7313e3SRoger Pau Monné 	KASSERT((page->flags & PG_FICTITIOUS) != 0,
174*bf7313e3SRoger Pau Monné 	    ("not fictitious %p", page));
175*bf7313e3SRoger Pau Monné 	KASSERT(page->wire_count == 1, ("wire_count not 1 %p", page));
176*bf7313e3SRoger Pau Monné 	KASSERT(vm_page_busied(page) == 0, ("page %p is busy", page));
177*bf7313e3SRoger Pau Monné 
178*bf7313e3SRoger Pau Monné 	if (*mres != NULL) {
179*bf7313e3SRoger Pau Monné 		oldm = *mres;
180*bf7313e3SRoger Pau Monné 		vm_page_lock(oldm);
181*bf7313e3SRoger Pau Monné 		vm_page_free(oldm);
182*bf7313e3SRoger Pau Monné 		vm_page_unlock(oldm);
183*bf7313e3SRoger Pau Monné 		*mres = NULL;
184*bf7313e3SRoger Pau Monné 	}
185*bf7313e3SRoger Pau Monné 
186*bf7313e3SRoger Pau Monné 	vm_page_insert(page, object, pidx);
187*bf7313e3SRoger Pau Monné 	page->valid = VM_PAGE_BITS_ALL;
188*bf7313e3SRoger Pau Monné 	vm_page_xbusy(page);
189*bf7313e3SRoger Pau Monné 	*mres = page;
190*bf7313e3SRoger Pau Monné 	return (VM_PAGER_OK);
191*bf7313e3SRoger Pau Monné }
192*bf7313e3SRoger Pau Monné 
193*bf7313e3SRoger Pau Monné /*----------------------- Privcmd char device methods ------------------------*/
194*bf7313e3SRoger Pau Monné static int
195*bf7313e3SRoger Pau Monné privcmd_mmap_single(struct cdev *cdev, vm_ooffset_t *offset, vm_size_t size,
196*bf7313e3SRoger Pau Monné     vm_object_t *object, int nprot)
197*bf7313e3SRoger Pau Monné {
198*bf7313e3SRoger Pau Monné 	struct privcmd_map *map;
199*bf7313e3SRoger Pau Monné 	int error;
200*bf7313e3SRoger Pau Monné 
201*bf7313e3SRoger Pau Monné 	map = malloc(sizeof(*map), M_PRIVCMD, M_WAITOK | M_ZERO);
202*bf7313e3SRoger Pau Monné 
203*bf7313e3SRoger Pau Monné 	map->size = OFF_TO_IDX(size);
204*bf7313e3SRoger Pau Monné 	map->pseudo_phys_res_id = 0;
205*bf7313e3SRoger Pau Monné 
206*bf7313e3SRoger Pau Monné 	map->pseudo_phys_res = bus_alloc_resource(privcmd_dev, SYS_RES_MEMORY,
207*bf7313e3SRoger Pau Monné 	    &map->pseudo_phys_res_id, 0, ~0, size, RF_ACTIVE);
208*bf7313e3SRoger Pau Monné 	if (map->pseudo_phys_res == NULL) {
209*bf7313e3SRoger Pau Monné 		free(map, M_PRIVCMD);
210*bf7313e3SRoger Pau Monné 		return (ENOMEM);
211*bf7313e3SRoger Pau Monné 	}
212*bf7313e3SRoger Pau Monné 
213*bf7313e3SRoger Pau Monné 	map->phys_base_addr = rman_get_start(map->pseudo_phys_res);
214*bf7313e3SRoger Pau Monné 
215*bf7313e3SRoger Pau Monné 	error = vm_phys_fictitious_reg_range(map->phys_base_addr,
216*bf7313e3SRoger Pau Monné 	    map->phys_base_addr + size, VM_MEMATTR_DEFAULT);
217*bf7313e3SRoger Pau Monné 	if (error) {
218*bf7313e3SRoger Pau Monné 		bus_release_resource(privcmd_dev, SYS_RES_MEMORY,
219*bf7313e3SRoger Pau Monné 		    map->pseudo_phys_res_id, map->pseudo_phys_res);
220*bf7313e3SRoger Pau Monné 		free(map, M_PRIVCMD);
221*bf7313e3SRoger Pau Monné 		return (error);
222*bf7313e3SRoger Pau Monné 	}
223*bf7313e3SRoger Pau Monné 
224*bf7313e3SRoger Pau Monné 	map->mem = cdev_pager_allocate(map, OBJT_MGTDEVICE, &privcmd_pg_ops,
225*bf7313e3SRoger Pau Monné 	    size, nprot, *offset, NULL);
226*bf7313e3SRoger Pau Monné 	if (map->mem == NULL) {
227*bf7313e3SRoger Pau Monné 		bus_release_resource(privcmd_dev, SYS_RES_MEMORY,
228*bf7313e3SRoger Pau Monné 		    map->pseudo_phys_res_id, map->pseudo_phys_res);
229*bf7313e3SRoger Pau Monné 		free(map, M_PRIVCMD);
230*bf7313e3SRoger Pau Monné 		return (ENOMEM);
231*bf7313e3SRoger Pau Monné 	}
232*bf7313e3SRoger Pau Monné 
233*bf7313e3SRoger Pau Monné 	*object = map->mem;
234*bf7313e3SRoger Pau Monné 
235*bf7313e3SRoger Pau Monné 	return (0);
236*bf7313e3SRoger Pau Monné }
237*bf7313e3SRoger Pau Monné 
238*bf7313e3SRoger Pau Monné static int
239*bf7313e3SRoger Pau Monné privcmd_ioctl(struct cdev *dev, unsigned long cmd, caddr_t arg,
240*bf7313e3SRoger Pau Monné 	      int mode, struct thread *td)
241*bf7313e3SRoger Pau Monné {
242*bf7313e3SRoger Pau Monné 	int error, i;
243*bf7313e3SRoger Pau Monné 
244*bf7313e3SRoger Pau Monné 	switch (cmd) {
245*bf7313e3SRoger Pau Monné 	case IOCTL_PRIVCMD_HYPERCALL: {
246*bf7313e3SRoger Pau Monné 		struct ioctl_privcmd_hypercall *hcall;
247*bf7313e3SRoger Pau Monné 
248*bf7313e3SRoger Pau Monné 		hcall = (struct ioctl_privcmd_hypercall *)arg;
249*bf7313e3SRoger Pau Monné 
250*bf7313e3SRoger Pau Monné 		error = privcmd_hypercall(hcall->op, hcall->arg[0],
251*bf7313e3SRoger Pau Monné 		    hcall->arg[1], hcall->arg[2], hcall->arg[3], hcall->arg[4]);
252*bf7313e3SRoger Pau Monné 		if (error >= 0) {
253*bf7313e3SRoger Pau Monné 			hcall->retval = error;
254*bf7313e3SRoger Pau Monné 			error = 0;
255*bf7313e3SRoger Pau Monné 		} else {
256*bf7313e3SRoger Pau Monné 			error = xen_translate_error(error);
257*bf7313e3SRoger Pau Monné 			hcall->retval = 0;
258*bf7313e3SRoger Pau Monné 		}
259*bf7313e3SRoger Pau Monné 		break;
260*bf7313e3SRoger Pau Monné 	}
261*bf7313e3SRoger Pau Monné 	case IOCTL_PRIVCMD_MMAPBATCH: {
262*bf7313e3SRoger Pau Monné 		struct ioctl_privcmd_mmapbatch *mmap;
263*bf7313e3SRoger Pau Monné 		vm_map_t map;
264*bf7313e3SRoger Pau Monné 		vm_map_entry_t entry;
265*bf7313e3SRoger Pau Monné 		vm_object_t mem;
266*bf7313e3SRoger Pau Monné 		vm_pindex_t index;
267*bf7313e3SRoger Pau Monné 		vm_prot_t prot;
268*bf7313e3SRoger Pau Monné 		boolean_t wired;
269*bf7313e3SRoger Pau Monné 		struct xen_add_to_physmap_range add;
270*bf7313e3SRoger Pau Monné 		xen_ulong_t *idxs;
271*bf7313e3SRoger Pau Monné 		xen_pfn_t *gpfns;
272*bf7313e3SRoger Pau Monné 		int *errs;
273*bf7313e3SRoger Pau Monné 		struct privcmd_map *umap;
274*bf7313e3SRoger Pau Monné 
275*bf7313e3SRoger Pau Monné 		mmap = (struct ioctl_privcmd_mmapbatch *)arg;
276*bf7313e3SRoger Pau Monné 
277*bf7313e3SRoger Pau Monné 		if ((mmap->num == 0) ||
278*bf7313e3SRoger Pau Monné 		    ((mmap->addr & PAGE_MASK) != 0)) {
279*bf7313e3SRoger Pau Monné 			error = EINVAL;
280*bf7313e3SRoger Pau Monné 			break;
281*bf7313e3SRoger Pau Monné 		}
282*bf7313e3SRoger Pau Monné 
283*bf7313e3SRoger Pau Monné 		map = &td->td_proc->p_vmspace->vm_map;
284*bf7313e3SRoger Pau Monné 		error = vm_map_lookup(&map, mmap->addr, VM_PROT_NONE, &entry,
285*bf7313e3SRoger Pau Monné 		    &mem, &index, &prot, &wired);
286*bf7313e3SRoger Pau Monné 		if (error != KERN_SUCCESS) {
287*bf7313e3SRoger Pau Monné 			error = EINVAL;
288*bf7313e3SRoger Pau Monné 			break;
289*bf7313e3SRoger Pau Monné 		}
290*bf7313e3SRoger Pau Monné 		if ((entry->start != mmap->addr) ||
291*bf7313e3SRoger Pau Monné 		    (entry->end != mmap->addr + (mmap->num * PAGE_SIZE))) {
292*bf7313e3SRoger Pau Monné 			vm_map_lookup_done(map, entry);
293*bf7313e3SRoger Pau Monné 			error = EINVAL;
294*bf7313e3SRoger Pau Monné 			break;
295*bf7313e3SRoger Pau Monné 		}
296*bf7313e3SRoger Pau Monné 		vm_map_lookup_done(map, entry);
297*bf7313e3SRoger Pau Monné 		if ((mem->type != OBJT_MGTDEVICE) ||
298*bf7313e3SRoger Pau Monné 		    (mem->un_pager.devp.ops != &privcmd_pg_ops)) {
299*bf7313e3SRoger Pau Monné 			error = EINVAL;
300*bf7313e3SRoger Pau Monné 			break;
301*bf7313e3SRoger Pau Monné 		}
302*bf7313e3SRoger Pau Monné 		umap = mem->handle;
303*bf7313e3SRoger Pau Monné 
304*bf7313e3SRoger Pau Monné 		add.domid = DOMID_SELF;
305*bf7313e3SRoger Pau Monné 		add.space = XENMAPSPACE_gmfn_foreign;
306*bf7313e3SRoger Pau Monné 		add.size = mmap->num;
307*bf7313e3SRoger Pau Monné 		add.foreign_domid = mmap->dom;
308*bf7313e3SRoger Pau Monné 
309*bf7313e3SRoger Pau Monné 		idxs = malloc(sizeof(*idxs) * mmap->num, M_PRIVCMD,
310*bf7313e3SRoger Pau Monné 		    M_WAITOK | M_ZERO);
311*bf7313e3SRoger Pau Monné 		gpfns = malloc(sizeof(*gpfns) * mmap->num, M_PRIVCMD,
312*bf7313e3SRoger Pau Monné 		    M_WAITOK | M_ZERO);
313*bf7313e3SRoger Pau Monné 		errs = malloc(sizeof(*errs) * mmap->num, M_PRIVCMD,
314*bf7313e3SRoger Pau Monné 		    M_WAITOK | M_ZERO);
315*bf7313e3SRoger Pau Monné 
316*bf7313e3SRoger Pau Monné 		set_xen_guest_handle(add.idxs, idxs);
317*bf7313e3SRoger Pau Monné 		set_xen_guest_handle(add.gpfns, gpfns);
318*bf7313e3SRoger Pau Monné 		set_xen_guest_handle(add.errs, errs);
319*bf7313e3SRoger Pau Monné 
320*bf7313e3SRoger Pau Monné 		error = copyin(&mmap->arr[0], idxs,
321*bf7313e3SRoger Pau Monné 		    sizeof(idxs[0]) * mmap->num);
322*bf7313e3SRoger Pau Monné 		if (error != 0)
323*bf7313e3SRoger Pau Monné 			goto mmap_out;
324*bf7313e3SRoger Pau Monné 
325*bf7313e3SRoger Pau Monné 		for (i = 0; i < mmap->num; i++)
326*bf7313e3SRoger Pau Monné 			gpfns[i] = atop(umap->phys_base_addr + i * PAGE_SIZE);
327*bf7313e3SRoger Pau Monné 
328*bf7313e3SRoger Pau Monné 		error = HYPERVISOR_memory_op(XENMEM_add_to_physmap_range, &add);
329*bf7313e3SRoger Pau Monné 		if (error) {
330*bf7313e3SRoger Pau Monné 			error = xen_translate_error(error);
331*bf7313e3SRoger Pau Monné 			goto mmap_out;
332*bf7313e3SRoger Pau Monné 		}
333*bf7313e3SRoger Pau Monné 
334*bf7313e3SRoger Pau Monné 		for (i = 0; i < mmap->num; i++) {
335*bf7313e3SRoger Pau Monné 			if (errs[i] != 0)
336*bf7313e3SRoger Pau Monné 				errs[i] = xen_translate_error(errs[i]);
337*bf7313e3SRoger Pau Monné 		}
338*bf7313e3SRoger Pau Monné 
339*bf7313e3SRoger Pau Monné 		/*
340*bf7313e3SRoger Pau Monné 		 * Save errs, so we know which pages have been
341*bf7313e3SRoger Pau Monné 		 * successfully mapped.
342*bf7313e3SRoger Pau Monné 		 */
343*bf7313e3SRoger Pau Monné 		umap->errs = errs;
344*bf7313e3SRoger Pau Monné 		umap->mapped = true;
345*bf7313e3SRoger Pau Monné 
346*bf7313e3SRoger Pau Monné 		error = copyout(errs, &mmap->err[0],
347*bf7313e3SRoger Pau Monné 		    sizeof(errs[0]) * mmap->num);
348*bf7313e3SRoger Pau Monné 
349*bf7313e3SRoger Pau Monné mmap_out:
350*bf7313e3SRoger Pau Monné 		free(idxs, M_PRIVCMD);
351*bf7313e3SRoger Pau Monné 		free(gpfns, M_PRIVCMD);
352*bf7313e3SRoger Pau Monné 		if (!umap->mapped)
353*bf7313e3SRoger Pau Monné 			free(errs, M_PRIVCMD);
354*bf7313e3SRoger Pau Monné 
355*bf7313e3SRoger Pau Monné 		break;
356*bf7313e3SRoger Pau Monné 	}
357*bf7313e3SRoger Pau Monné 
358*bf7313e3SRoger Pau Monné 	default:
359*bf7313e3SRoger Pau Monné 		error = ENOSYS;
360*bf7313e3SRoger Pau Monné 		break;
361*bf7313e3SRoger Pau Monné 	}
362*bf7313e3SRoger Pau Monné 
363*bf7313e3SRoger Pau Monné 	return (error);
364*bf7313e3SRoger Pau Monné }
365*bf7313e3SRoger Pau Monné 
366*bf7313e3SRoger Pau Monné /*------------------ Private Device Attachment Functions  --------------------*/
367*bf7313e3SRoger Pau Monné static void
368*bf7313e3SRoger Pau Monné privcmd_identify(driver_t *driver, device_t parent)
369*bf7313e3SRoger Pau Monné {
370*bf7313e3SRoger Pau Monné 
371*bf7313e3SRoger Pau Monné 	KASSERT(xen_domain(),
372*bf7313e3SRoger Pau Monné 	    ("Trying to attach privcmd device on non Xen domain"));
373*bf7313e3SRoger Pau Monné 
374*bf7313e3SRoger Pau Monné 	if (BUS_ADD_CHILD(parent, 0, "privcmd", 0) == NULL)
375*bf7313e3SRoger Pau Monné 		panic("unable to attach privcmd user-space device");
376*bf7313e3SRoger Pau Monné }
377*bf7313e3SRoger Pau Monné 
378*bf7313e3SRoger Pau Monné static int
379*bf7313e3SRoger Pau Monné privcmd_probe(device_t dev)
380*bf7313e3SRoger Pau Monné {
381*bf7313e3SRoger Pau Monné 
382*bf7313e3SRoger Pau Monné 	privcmd_dev = dev;
383*bf7313e3SRoger Pau Monné 	device_set_desc(dev, "Xen privileged interface user-space device");
384*bf7313e3SRoger Pau Monné 	return (BUS_PROBE_NOWILDCARD);
385*bf7313e3SRoger Pau Monné }
386*bf7313e3SRoger Pau Monné 
387*bf7313e3SRoger Pau Monné static int
388*bf7313e3SRoger Pau Monné privcmd_attach(device_t dev)
389*bf7313e3SRoger Pau Monné {
390*bf7313e3SRoger Pau Monné 
391*bf7313e3SRoger Pau Monné 	make_dev_credf(MAKEDEV_ETERNAL, &privcmd_devsw, 0, NULL, UID_ROOT,
392*bf7313e3SRoger Pau Monné 	    GID_WHEEL, 0600, "xen/privcmd");
393*bf7313e3SRoger Pau Monné 	return (0);
394*bf7313e3SRoger Pau Monné }
395*bf7313e3SRoger Pau Monné 
396*bf7313e3SRoger Pau Monné /*-------------------- Private Device Attachment Data  -----------------------*/
397*bf7313e3SRoger Pau Monné static device_method_t privcmd_methods[] = {
398*bf7313e3SRoger Pau Monné 	DEVMETHOD(device_identify,	privcmd_identify),
399*bf7313e3SRoger Pau Monné 	DEVMETHOD(device_probe,		privcmd_probe),
400*bf7313e3SRoger Pau Monné 	DEVMETHOD(device_attach,	privcmd_attach),
401*bf7313e3SRoger Pau Monné 
402*bf7313e3SRoger Pau Monné 	DEVMETHOD_END
403*bf7313e3SRoger Pau Monné };
404*bf7313e3SRoger Pau Monné 
405*bf7313e3SRoger Pau Monné static driver_t privcmd_driver = {
406*bf7313e3SRoger Pau Monné 	"privcmd",
407*bf7313e3SRoger Pau Monné 	privcmd_methods,
408*bf7313e3SRoger Pau Monné 	0,
409*bf7313e3SRoger Pau Monné };
410*bf7313e3SRoger Pau Monné 
411*bf7313e3SRoger Pau Monné devclass_t privcmd_devclass;
412*bf7313e3SRoger Pau Monné 
413*bf7313e3SRoger Pau Monné DRIVER_MODULE(privcmd, xenpv, privcmd_driver, privcmd_devclass, 0, 0);
414*bf7313e3SRoger Pau Monné MODULE_DEPEND(privcmd, xenpv, 1, 1, 1);
415