34#include <sys/malloc.h>
35#include <sys/kernel.h>
38#include <sys/rwlock.h>
39#include <sys/selinfo.h>
43#include <sys/ioccom.h>
46#include <sys/module.h>
48#include <sys/bitset.h>
51#include <vm/vm_param.h>
52#include <vm/vm_extern.h>
53#include <vm/vm_kern.h>
54#include <vm/vm_page.h>
56#include <vm/vm_object.h>
57#include <vm/vm_pager.h>
59#include <machine/md_var.h>
61#include <xen/xen-os.h>
62#include <xen/hypervisor.h>
63#include <xen/privcmd.h>
66MALLOC_DEFINE(M_PRIVCMD,
"privcmd_dev",
"Xen privcmd user-space device");
68#define MAX_DMOP_BUFFERS 16
85 .d_version = D_VERSION,
92static int privcmd_pg_ctor(
void *handle, vm_ooffset_t size, vm_prot_t prot,
93 vm_ooffset_t foff,
struct ucred *cred, u_short *color);
96 int prot, vm_page_t *mres);
113 vm_ooffset_t foff,
struct ucred *cred, u_short *color)
122 struct xen_remove_from_physmap rm = { .domid = DOMID_SELF };
124 int error __diagused;
132 if (map->
mapped ==
true) {
133 VM_OBJECT_WLOCK(map->
mem);
135 for (i = 0; i < map->
size; i++) {
136 m = vm_page_lookup(map->
mem, i);
139 if (vm_page_busy_acquire(m, VM_ALLOC_WAITFAIL) == 0)
141 cdev_pager_free_page(map->
mem, m);
143 VM_OBJECT_WUNLOCK(map->
mem);
145 for (i = 0; i < map->
size; i++) {
147 HYPERVISOR_memory_op(XENMEM_remove_from_physmap, &rm);
149 free(map->err, M_PRIVCMD);
154 KASSERT(error == 0, (
"Unable to release memory resource: %d", error));
156 free(map, M_PRIVCMD);
161 int prot, vm_page_t *mres)
168 return (VM_PAGER_FAIL);
170 pidx = OFF_TO_IDX(offset);
171 if (pidx >= map->
size || BIT_ISSET(map->
size, pidx, map->err))
172 return (VM_PAGER_FAIL);
176 return (VM_PAGER_FAIL);
178 KASSERT((page->flags & PG_FICTITIOUS) != 0,
179 (
"not fictitious %p", page));
180 KASSERT(vm_page_wired(page), (
"page %p not wired", page));
181 KASSERT(!vm_page_busied(page), (
"page %p is busy", page));
183 vm_page_busy_acquire(page, 0);
187 vm_page_replace(page,
object, pidx, *mres);
189 vm_page_insert(page,
object, pidx);
191 return (VM_PAGER_OK);
197 vm_object_t *
object,
int nprot)
201 map = malloc(
sizeof(*map), M_PRIVCMD, M_WAITOK | M_ZERO);
209 free(map, M_PRIVCMD);
215 size, nprot, *offset, NULL);
216 if (map->
mem == NULL) {
219 free(map, M_PRIVCMD);
232 vm_map_entry_t entry;
240 if ((num == 0) || ((addr & PAGE_MASK) != 0))
243 map = &td->td_proc->p_vmspace->vm_map;
244 error = vm_map_lookup(&map, addr, VM_PROT_NONE, &entry, &
mem, &pindex,
246 if (error != KERN_SUCCESS || (entry->start != addr) ||
247 (entry->end != addr + (num * PAGE_SIZE)))
250 vm_map_lookup_done(map, entry);
251 if ((
mem->type != OBJT_MGTDEVICE) ||
257 umap->err = BITSET_ALLOC(num, M_PRIVCMD, M_WAITOK | M_ZERO);
264 int mode,
struct thread *td)
271 error = devfs_get_cdevpriv(&data);
281 case IOCTL_PRIVCMD_HYPERCALL: {
282 struct ioctl_privcmd_hypercall *hcall;
284 hcall = (
struct ioctl_privcmd_hypercall *)arg;
287 if (u->
dom != DOMID_INVALID) {
298 if (cpu_stdext_feature & CPUID_STDEXT_SMAP)
301 error = privcmd_hypercall(hcall->op, hcall->arg[0],
302 hcall->arg[1], hcall->arg[2], hcall->arg[3], hcall->arg[4]);
304 if (cpu_stdext_feature & CPUID_STDEXT_SMAP)
308 hcall->retval = error;
311 error = xen_translate_error(error);
316 case IOCTL_PRIVCMD_MMAPBATCH: {
317 struct ioctl_privcmd_mmapbatch *mmap;
318 struct xen_add_to_physmap_range add;
326 mmap = (
struct ioctl_privcmd_mmapbatch *)arg;
328 if (u->
dom != DOMID_INVALID && u->
dom != mmap->dom) {
339 add.domid = DOMID_SELF;
340 add.space = XENMAPSPACE_gmfn_foreign;
341 add.foreign_domid = mmap->dom;
347 num = MIN(mmap->num, UINT16_MAX);
349 idxs = malloc(
sizeof(*idxs) * num, M_PRIVCMD, M_WAITOK);
350 gpfns = malloc(
sizeof(*gpfns) * num, M_PRIVCMD, M_WAITOK);
351 errs = malloc(
sizeof(*errs) * num, M_PRIVCMD, M_WAITOK);
353 set_xen_guest_handle(add.idxs, idxs);
354 set_xen_guest_handle(add.gpfns, gpfns);
355 set_xen_guest_handle(add.errs, errs);
357 for (index = 0; index < mmap->num; index += num) {
358 num = MIN(mmap->num - index, UINT16_MAX);
361 error = copyin(&mmap->arr[index], idxs,
362 sizeof(idxs[0]) * num);
366 for (i = 0; i < num; i++)
368 (i + index) * PAGE_SIZE);
370 bzero(errs,
sizeof(*errs) * num);
372 error = HYPERVISOR_memory_op(
373 XENMEM_add_to_physmap_range, &add);
375 error = xen_translate_error(error);
379 for (i = 0; i < num; i++) {
381 errs[i] = xen_translate_error(errs[i]);
384 BIT_SET(mmap->num, index + i,
389 error = copyout(errs, &mmap->err[index],
390 sizeof(errs[0]) * num);
398 free(idxs, M_PRIVCMD);
399 free(gpfns, M_PRIVCMD);
400 free(errs, M_PRIVCMD);
402 free(umap->err, M_PRIVCMD);
406 case IOCTL_PRIVCMD_MMAP_RESOURCE: {
407 struct ioctl_privcmd_mmapresource *mmap;
408 struct xen_mem_acquire_resource adq;
412 mmap = (
struct ioctl_privcmd_mmapresource *)arg;
414 if (u->
dom != DOMID_INVALID && u->
dom != mmap->dom) {
419 bzero(&adq,
sizeof(adq));
421 adq.domid = mmap->dom;
422 adq.type = mmap->type;
426 if (mmap->addr == 0 && mmap->num == 0) {
427 error = HYPERVISOR_memory_op(XENMEM_acquire_resource,
430 error = xen_translate_error(error);
432 mmap->num = adq.nr_frames;
442 adq.nr_frames = mmap->num;
443 adq.frame = mmap->idx;
445 gpfns = malloc(
sizeof(*gpfns) * mmap->num, M_PRIVCMD, M_WAITOK);
446 for (i = 0; i < mmap->num; i++)
448 set_xen_guest_handle(adq.frame_list, gpfns);
450 error = HYPERVISOR_memory_op(XENMEM_acquire_resource, &adq);
452 error = xen_translate_error(error);
456 free(gpfns, M_PRIVCMD);
458 free(umap->err, M_PRIVCMD);
462 case IOCTL_PRIVCMD_DM_OP: {
463 const struct ioctl_privcmd_dmop *dmop;
464 struct privcmd_dmop_buf *bufs;
465 struct xen_dm_op_buf *hbufs;
467 dmop = (
struct ioctl_privcmd_dmop *)arg;
469 if (u->
dom != DOMID_INVALID && u->
dom != dmop->dom) {
482 bufs = malloc(
sizeof(*bufs) * dmop->num, M_PRIVCMD, M_WAITOK);
484 error = copyin(dmop->ubufs, bufs,
sizeof(*bufs) * dmop->num);
486 free(bufs, M_PRIVCMD);
490 hbufs = malloc(
sizeof(*hbufs) * dmop->num, M_PRIVCMD, M_WAITOK);
491 for (i = 0; i < dmop->num; i++) {
492 set_xen_guest_handle(hbufs[i].h, bufs[i].uptr);
493 hbufs[i].size = bufs[i].size;
497 if (cpu_stdext_feature & CPUID_STDEXT_SMAP)
500 error = HYPERVISOR_dm_op(dmop->dom, dmop->num, hbufs);
502 if (cpu_stdext_feature & CPUID_STDEXT_SMAP)
506 error = xen_translate_error(error);
508 free(bufs, M_PRIVCMD);
509 free(hbufs, M_PRIVCMD);
514 case IOCTL_PRIVCMD_RESTRICT: {
518 dom = *(domid_t *)arg;
520 error = devfs_get_cdevpriv((
void **)&u);
524 if (u->
dom != DOMID_INVALID && u->
dom !=
dom) {
544 free(arg, M_PRIVCMD);
553 u = malloc(
sizeof(*u), M_PRIVCMD, M_WAITOK);
554 u->
dom = DOMID_INVALID;
570 KASSERT(xen_domain(),
571 (
"Trying to attach privcmd device on non Xen domain"));
573 if (BUS_ADD_CHILD(parent, 0,
"privcmd", 0) == NULL)
574 panic(
"unable to attach privcmd user-space device");
582 device_set_desc(dev,
"Xen privileged interface user-space device");
583 return (BUS_PROBE_NOWILDCARD);
590 make_dev_credf(MAKEDEV_ETERNAL, &
privcmd_devsw, 0, NULL, UID_ROOT,
591 GID_WHEEL, 0600,
"xen/privcmd");
static void user_release(void *arg)
static int privcmd_pg_fault(vm_object_t object, vm_ooffset_t offset, int prot, vm_page_t *mres)
static int privcmd_pg_ctor(void *handle, vm_ooffset_t size, vm_prot_t prot, vm_ooffset_t foff, struct ucred *cred, u_short *color)
static struct privcmd_map * setup_virtual_area(struct thread *td, unsigned long addr, unsigned long num)
static d_mmap_single_t privcmd_mmap_single
static device_method_t privcmd_methods[]
static struct cdev_pager_ops privcmd_pg_ops
static driver_t privcmd_driver
static d_open_t privcmd_open
DRIVER_MODULE(privcmd, xenpv, privcmd_driver, privcmd_devclass, 0, 0)
static int privcmd_probe(device_t dev)
devclass_t privcmd_devclass
static d_ioctl_t privcmd_ioctl
MALLOC_DEFINE(M_PRIVCMD, "privcmd_dev", "Xen privcmd user-space device")
static struct cdevsw privcmd_devsw
MODULE_DEPEND(privcmd, xenpv, 1, 1, 1)
static void privcmd_identify(driver_t *driver, device_t parent)
static device_t privcmd_dev
static int privcmd_attach(device_t dev)
static void privcmd_pg_dtor(void *handle)
struct resource * pseudo_phys_res
vm_paddr_t phys_base_addr
struct resource * xenmem_alloc(device_t dev, int *res_id, size_t size)
int xenmem_free(device_t dev, int res_id, struct resource *res)