Skip to content

Commit

Permalink
support VFIO_USER_REGION_WRITE_MULTI
Browse files Browse the repository at this point in the history
Signed-off-by: John Levon <[email protected]>
  • Loading branch information
jlevon committed Aug 16, 2022
1 parent d307dbc commit c8430a7
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 4 deletions.
16 changes: 16 additions & 0 deletions include/vfio-user.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ enum vfio_user_command {
VFIO_USER_DMA_WRITE = 12,
VFIO_USER_DEVICE_RESET = 13,
VFIO_USER_DIRTY_PAGES = 14,
VFIO_USER_REGION_WRITE_MULTI = 15,
VFIO_USER_MAX,
};

Expand Down Expand Up @@ -226,6 +227,21 @@ struct vfio_user_bitmap_range {

#endif /* VFIO_REGION_TYPE_MIGRATION */

#define VFIO_USER_MULTI_DATA 8
#define VFIO_USER_MULTI_MAX 200

struct vfio_user_write_multi_data {
uint64_t offset;
uint32_t region;
uint32_t count;
char data[VFIO_USER_MULTI_DATA];
} __attribute__((packed));

struct vfio_user_write_multi {
uint64_t wr_cnt;
struct vfio_user_write_multi_data wrs[VFIO_USER_MULTI_MAX];
} __attribute__((packed));

#ifdef __cplusplus
}
#endif
Expand Down
89 changes: 85 additions & 4 deletions lib/libvfio-user.c
Original file line number Diff line number Diff line change
Expand Up @@ -264,10 +264,27 @@ is_valid_region_access(vfu_ctx_t *vfu_ctx, size_t size, uint16_t cmd,
return false;
}

if (cmd == VFIO_USER_REGION_WRITE && size - sizeof(*ra) != ra->count) {
vfu_log(vfu_ctx, LOG_ERR, "region write count too small: "
"expected %lu, got %u", size - sizeof(*ra), ra->count);
return false;
switch (cmd) {
case VFIO_USER_REGION_WRITE:
if (size - sizeof(*ra) != ra->count) {
vfu_log(vfu_ctx, LOG_ERR, "region write count too small: "
"expected %lu, got %u", size - sizeof(*ra), ra->count);
return false;
}

break;

case VFIO_USER_REGION_WRITE_MULTI:
if (ra->count > VFIO_USER_MULTI_DATA) {
vfu_log(vfu_ctx, LOG_ERR, "region write count too large: "
"expected %lu, got %u", size - sizeof(*ra), ra->count);
return false;
}

break;

default:
break;
}

index = ra->region;
Expand Down Expand Up @@ -350,6 +367,61 @@ handle_region_access(vfu_ctx_t *vfu_ctx, vfu_msg_t *msg)
return 0;
}

static int
handle_region_write_multi(vfu_ctx_t *vfu_ctx, vfu_msg_t *msg)
{
struct vfio_user_write_multi *wm = msg->in.iov.iov_base;
ssize_t ret;
char *buf;

assert(vfu_ctx != NULL);
assert(msg != NULL);

// FIXME: validate properly (?)

if (wm->wr_cnt > VFIO_USER_MULTI_MAX) {
return ERROR_INT(EINVAL);
}

if (msg->in.iov.iov_len < sizeof(*wm)) {
return ERROR_INT(EINVAL);
}

for (size_t i = 0; i < wm->wr_cnt; i++) {
struct vfio_user_region_access *in_ra;

/* Re-use the very similar type. */
in_ra = (struct vfio_user_region_access *)&wm->wrs[i];

/*
* We already checked total length so can be sure each entry is at least
* big enough.
*/
if (!is_valid_region_access(vfu_ctx, sizeof(wm->wrs[i]),
msg->hdr.cmd, in_ra)) {
return ERROR_INT(EINVAL);
}

if (in_ra->count == 0) {
continue;
}

buf = (char *)(&in_ra->data);

ret = region_access(vfu_ctx, in_ra->region, buf, in_ra->count,
in_ra->offset, true);
if (ret != in_ra->count) {
/* FIXME we should return whatever has been accessed, not an error */
if (ret >= 0) {
ret = ERROR_INT(EINVAL);
}
return ret;
}
}

return 0;
}

static int
handle_device_get_info(vfu_ctx_t *vfu_ctx, vfu_msg_t *msg)
{
Expand Down Expand Up @@ -1146,6 +1218,11 @@ handle_request(vfu_ctx_t *vfu_ctx, vfu_msg_t *msg)
ret = handle_region_access(vfu_ctx, msg);
break;

case VFIO_USER_REGION_WRITE_MULTI:
ret = handle_region_write_multi(vfu_ctx, msg);
break;


case VFIO_USER_DEVICE_RESET:
vfu_log(vfu_ctx, LOG_INFO, "device reset by client");
ret = handle_device_reset(vfu_ctx, VFU_RESET_DEVICE);
Expand Down Expand Up @@ -1334,6 +1411,10 @@ command_needs_quiesce(vfu_ctx_t *vfu_ctx, const vfu_msg_t *msg)
return true;
}
break;

case VFIO_USER_REGION_WRITE_MULTI:
/* FIXME */
return false;
}

return false;
Expand Down

0 comments on commit c8430a7

Please sign in to comment.