aboutsummaryrefslogtreecommitdiff
path: root/lib/libvfio-user.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libvfio-user.c')
-rw-r--r--lib/libvfio-user.c107
1 files changed, 68 insertions, 39 deletions
diff --git a/lib/libvfio-user.c b/lib/libvfio-user.c
index 307f909..99a115d 100644
--- a/lib/libvfio-user.c
+++ b/lib/libvfio-user.c
@@ -468,30 +468,40 @@ consume_fd(int *fds, size_t nr_fds, size_t index)
int
handle_dma_map(vfu_ctx_t *vfu_ctx, vfu_msg_t *msg,
- struct vfio_user_dma_region *region)
+ struct vfio_user_dma_map *dma_map)
{
char rstr[1024];
int fd = -1;
int ret;
+ uint32_t prot = 0;
assert(vfu_ctx != NULL);
assert(msg != NULL);
- assert(region != NULL);
+ assert(dma_map != NULL);
- if (msg->in_size != sizeof(*region)) {
- vfu_log(vfu_ctx, LOG_ERR, "bad size of DMA map region %zu",
- msg->in_size);
+ if (msg->in_size < sizeof(*dma_map) || dma_map->argsz < sizeof(*dma_map)) {
+ vfu_log(vfu_ctx, LOG_ERR, "bad DMA map region size=%zu argsz=%u",
+ msg->in_size, dma_map->argsz);
return ERROR_INT(EINVAL);
}
- snprintf(rstr, sizeof(rstr),
- "[%#lx, %#lx) offset=%#lx prot=%#x flags=%#x",
- region->addr, region->addr + region->size, region->offset,
- region->prot, region->flags);
+ snprintf(rstr, sizeof(rstr), "[%#lx, %#lx) offset=%#lx flags=%#x",
+ dma_map->addr, dma_map->addr + dma_map->size, dma_map->offset,
+ dma_map->flags);
vfu_log(vfu_ctx, LOG_DEBUG, "adding DMA region %s", rstr);
- if (region->flags == VFIO_USER_F_DMA_REGION_MAPPABLE) {
+ if (dma_map->flags & VFIO_USER_F_DMA_REGION_READ) {
+ prot |= PROT_READ;
+ dma_map->flags &= ~VFIO_USER_F_DMA_REGION_READ;
+ }
+
+ if (dma_map->flags & VFIO_USER_F_DMA_REGION_WRITE) {
+ prot |= PROT_WRITE;
+ dma_map->flags &= ~VFIO_USER_F_DMA_REGION_WRITE;
+ }
+
+ if (dma_map->flags == VFIO_USER_F_DMA_REGION_MAPPABLE) {
fd = consume_fd(msg->in_fds, msg->nr_in_fds, 0);
if (fd < 0) {
vfu_log(vfu_ctx, LOG_ERR,
@@ -499,11 +509,13 @@ handle_dma_map(vfu_ctx_t *vfu_ctx, vfu_msg_t *msg,
rstr);
return -1;
}
+ } else if (dma_map->flags != 0) {
+ vfu_log(vfu_ctx, LOG_ERR, "bad flags=%#x", dma_map->flags);
}
- ret = dma_controller_add_region(vfu_ctx->dma, (void *)region->addr,
- region->size, fd, region->offset,
- region->prot);
+ ret = dma_controller_add_region(vfu_ctx->dma, (void *)dma_map->addr,
+ dma_map->size, fd, dma_map->offset,
+ prot);
if (ret < 0) {
ret = errno;
vfu_log(vfu_ctx, LOG_ERR, "failed to add DMA region %s: %m", rstr);
@@ -521,31 +533,41 @@ handle_dma_map(vfu_ctx_t *vfu_ctx, vfu_msg_t *msg,
int
handle_dma_unmap(vfu_ctx_t *vfu_ctx, vfu_msg_t *msg,
- struct vfio_user_dma_region *region)
+ struct vfio_user_dma_unmap *dma_unmap)
{
int ret;
- char *bitmap;
+ char *bitmap = NULL;
char rstr[1024];
assert(vfu_ctx != NULL);
assert(msg != NULL);
- assert(region != NULL);
+ assert(dma_unmap != NULL);
- if (msg->in_size < sizeof(*region)) {
- vfu_log(vfu_ctx, LOG_ERR, "bad size of DMA unmap region %zu",
- msg->in_size);
+ if (msg->in_size < sizeof(*dma_unmap) || dma_unmap->argsz < sizeof(*dma_unmap)) {
+ vfu_log(vfu_ctx, LOG_ERR, "bad DMA unmap region size=%zu argsz=%u",
+ msg->in_size, dma_unmap->argsz);
return ERROR_INT(EINVAL);
}
- snprintf(rstr, sizeof(rstr), "[%#lx, %#lx) offset=%#lx prot=%#x flags=%#x",
- region->addr, region->addr + region->size,
- region->offset, region->prot, region->flags);
+ snprintf(rstr, sizeof(rstr), "[%#lx, %#lx) flags=%#x",
+ dma_unmap->addr, dma_unmap->addr + dma_unmap->size, dma_unmap->flags);
vfu_log(vfu_ctx, LOG_DEBUG, "removing DMA region %s", rstr);
- if (region->flags == VFIO_DMA_UNMAP_FLAG_GET_DIRTY_BITMAP) {
- if (msg->in_size < sizeof(*region) + sizeof(struct vfio_user_bitmap)) {
- vfu_log(vfu_ctx, LOG_ERR, "bad message size %#lx", msg->in_size);
+ msg->out_size = sizeof(*dma_unmap);
+
+ if (dma_unmap->flags == VFIO_DMA_UNMAP_FLAG_GET_DIRTY_BITMAP) {
+ if (msg->in_size < sizeof(*dma_unmap) + sizeof(*dma_unmap->bitmap)
+ || dma_unmap->argsz < sizeof(*dma_unmap) + sizeof(*dma_unmap->bitmap) + dma_unmap->bitmap->size) {
+ vfu_log(vfu_ctx, LOG_ERR, "bad message size=%#lx argsz=%#x",
+ msg->in_size, dma_unmap->argsz);
+
+ /*
+ * Ideally we should set argsz in the reply and fail the request
+ * with a struct vfio_user_dma_unmap payload, however this isn't
+ * currently supported. Instead, we simply fail the request,
+ * that's what VFIO does anyway.
+ */
return ERROR_INT(EINVAL);
}
/*
@@ -554,28 +576,35 @@ handle_dma_unmap(vfu_ctx_t *vfu_ctx, vfu_msg_t *msg,
* the DMA controller.
*/
ret = dma_controller_dirty_page_get(vfu_ctx->dma,
- (vfu_dma_addr_t)region->addr,
- region->size,
- region->bitmap->pgsize,
- region->bitmap->size,
+ (vfu_dma_addr_t)dma_unmap->addr,
+ dma_unmap->size,
+ dma_unmap->bitmap->pgsize,
+ dma_unmap->bitmap->size,
&bitmap);
if (ret < 0) {
vfu_log(vfu_ctx, LOG_ERR, "failed to get dirty page bitmap: %m");
return -1;
}
- msg->out_data = malloc(region->bitmap->size);
- if (msg->out_data == NULL) {
- return ERROR_INT(ENOMEM);
- }
- memcpy(msg->out_data, bitmap, region->bitmap->size);
- msg->out_size = region->bitmap->size;
- } else if (region->flags != 0) {
- vfu_log(vfu_ctx, LOG_ERR, "bad flags=%#x", region->flags);
+ msg->out_size += sizeof(*dma_unmap->bitmap) + dma_unmap->bitmap->size;
+ } else if (dma_unmap->flags != 0) {
+ vfu_log(vfu_ctx, LOG_ERR, "bad flags=%#x", dma_unmap->flags);
return ERROR_INT(ENOTSUP);
}
+
+ msg->out_data = malloc(msg->out_size);
+ if (msg->out_data == NULL) {
+ return ERROR_INT(ENOMEM);
+ }
+ memcpy(msg->out_data, dma_unmap, sizeof(*dma_unmap));
+
+ if (dma_unmap->flags & VFIO_DMA_UNMAP_FLAG_GET_DIRTY_BITMAP) {
+ memcpy(msg->out_data + sizeof(*dma_unmap), dma_unmap->bitmap, sizeof(*dma_unmap->bitmap));
+ memcpy(msg->out_data + sizeof(*dma_unmap) + sizeof(*dma_unmap->bitmap), bitmap, dma_unmap->bitmap->size);
+ }
+
ret = dma_controller_remove_region(vfu_ctx->dma,
- (void *)region->addr,
- region->size,
+ (void *)dma_unmap->addr,
+ dma_unmap->size,
vfu_ctx->dma_unregister,
vfu_ctx);
if (ret < 0) {