xen/privcmd: implement the map resource ioctl

The interface is mostly the same as the Linux ioctl, so that we don't
need to modify the user-space libraries that make use of it.

The ioctl is just a proxy for the XENMEM_acquire_resource hypercall.

Sponsored by:	Citrix Systems R&D
This commit is contained in:
Roger Pau Monne 2020-06-23 11:36:19 +02:00 committed by Roger Pau Monné
parent 147e593921
commit 658860e2d0
2 changed files with 67 additions and 0 deletions

View File

@ -372,7 +372,59 @@ privcmd_ioctl(struct cdev *dev, unsigned long cmd, caddr_t arg,
break;
}
case IOCTL_PRIVCMD_MMAP_RESOURCE: {
struct ioctl_privcmd_mmapresource *mmap;
struct xen_mem_acquire_resource adq;
xen_pfn_t *gpfns;
struct privcmd_map *umap;
mmap = (struct ioctl_privcmd_mmapresource *)arg;
bzero(&adq, sizeof(adq));
adq.domid = mmap->dom;
adq.type = mmap->type;
adq.id = mmap->id;
/* Shortcut for getting the resource size. */
if (mmap->addr == 0 && mmap->num == 0) {
error = HYPERVISOR_memory_op(XENMEM_acquire_resource,
&adq);
if (error != 0) {
error = xen_translate_error(error);
break;
}
error = copyout(&adq.nr_frames, &mmap->num,
sizeof(mmap->num));
break;
}
umap = setup_virtual_area(td, mmap->addr, mmap->num);
if (umap == NULL) {
error = EINVAL;
break;
}
adq.nr_frames = mmap->num;
adq.frame = mmap->idx;
gpfns = malloc(sizeof(*gpfns) * mmap->num, M_PRIVCMD, M_WAITOK);
for (i = 0; i < mmap->num; i++)
gpfns[i] = atop(umap->phys_base_addr) + i;
set_xen_guest_handle(adq.frame_list, gpfns);
error = HYPERVISOR_memory_op(XENMEM_acquire_resource, &adq);
if (error != 0)
error = xen_translate_error(error);
else
umap->mapped = true;
free(gpfns, M_PRIVCMD);
if (!umap->mapped)
free(umap->err, M_PRIVCMD);
break;
}
default:
error = ENOSYS;
break;

View File

@ -50,9 +50,24 @@ struct ioctl_privcmd_mmapbatch {
int *err; /* array of error codes */
};
struct ioctl_privcmd_mmapresource {
domid_t dom; /* target domain */
unsigned int type; /* type of resource to map */
unsigned int id; /* type-specific resource identifier */
unsigned int idx; /* the index of the initial frame to be mapped */
unsigned long num; /* number of frames of the resource to be mapped */
unsigned long addr; /* physical address to map into */
/*
* Note: issuing an ioctl with num = addr = 0 will return the size of
* the resource.
*/
};
#define IOCTL_PRIVCMD_HYPERCALL \
_IOWR('E', 0, struct ioctl_privcmd_hypercall)
#define IOCTL_PRIVCMD_MMAPBATCH \
_IOWR('E', 1, struct ioctl_privcmd_mmapbatch)
#define IOCTL_PRIVCMD_MMAP_RESOURCE \
_IOW('E', 2, struct ioctl_privcmd_mmapresource)
#endif /* !__XEN_PRIVCMD_H__ */