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