Skip to content

Commit aa183f9

Browse files
committed
support VFIO_USER_REGION_WRITE_MULTI
FIXME: needs work Signed-off-by: John Levon <[email protected]>
1 parent d307dbc commit aa183f9

File tree

3 files changed

+104
-5
lines changed

3 files changed

+104
-5
lines changed

include/vfio-user.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ enum vfio_user_command {
6767
VFIO_USER_DMA_WRITE = 12,
6868
VFIO_USER_DEVICE_RESET = 13,
6969
VFIO_USER_DIRTY_PAGES = 14,
70+
VFIO_USER_REGION_WRITE_MULTI = 15,
7071
VFIO_USER_MAX,
7172
};
7273

@@ -226,6 +227,21 @@ struct vfio_user_bitmap_range {
226227

227228
#endif /* VFIO_REGION_TYPE_MIGRATION */
228229

230+
#define VFIO_USER_MULTI_DATA 8
231+
#define VFIO_USER_MULTI_MAX 200
232+
233+
struct vfio_user_write_multi_data {
234+
uint64_t offset;
235+
uint32_t region;
236+
uint32_t count;
237+
char data[VFIO_USER_MULTI_DATA];
238+
} __attribute__((packed));
239+
240+
struct vfio_user_write_multi {
241+
uint64_t wr_cnt;
242+
struct vfio_user_write_multi_data wrs[VFIO_USER_MULTI_MAX];
243+
} __attribute__((packed));
244+
229245
#ifdef __cplusplus
230246
}
231247
#endif

lib/libvfio-user.c

Lines changed: 85 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -264,10 +264,27 @@ is_valid_region_access(vfu_ctx_t *vfu_ctx, size_t size, uint16_t cmd,
264264
return false;
265265
}
266266

267-
if (cmd == VFIO_USER_REGION_WRITE && size - sizeof(*ra) != ra->count) {
268-
vfu_log(vfu_ctx, LOG_ERR, "region write count too small: "
269-
"expected %lu, got %u", size - sizeof(*ra), ra->count);
270-
return false;
267+
switch (cmd) {
268+
case VFIO_USER_REGION_WRITE:
269+
if (size - sizeof(*ra) != ra->count) {
270+
vfu_log(vfu_ctx, LOG_ERR, "region write count too small: "
271+
"expected %lu, got %u", size - sizeof(*ra), ra->count);
272+
return false;
273+
}
274+
275+
break;
276+
277+
case VFIO_USER_REGION_WRITE_MULTI:
278+
if (ra->count > VFIO_USER_MULTI_DATA) {
279+
vfu_log(vfu_ctx, LOG_ERR, "region write count too large: "
280+
"expected %lu, got %u", size - sizeof(*ra), ra->count);
281+
return false;
282+
}
283+
284+
break;
285+
286+
default:
287+
break;
271288
}
272289

273290
index = ra->region;
@@ -350,6 +367,61 @@ handle_region_access(vfu_ctx_t *vfu_ctx, vfu_msg_t *msg)
350367
return 0;
351368
}
352369

370+
static int
371+
handle_region_write_multi(vfu_ctx_t *vfu_ctx, vfu_msg_t *msg)
372+
{
373+
struct vfio_user_write_multi *wm = msg->in.iov.iov_base;
374+
ssize_t ret;
375+
char *buf;
376+
377+
assert(vfu_ctx != NULL);
378+
assert(msg != NULL);
379+
380+
// FIXME: validate properly (?)
381+
382+
if (msg->in.iov.iov_len < sizeof(*wm)) {
383+
return ERROR_INT(EINVAL);
384+
}
385+
386+
if (wm->wr_cnt > VFIO_USER_MULTI_MAX) {
387+
return ERROR_INT(EINVAL);
388+
}
389+
390+
for (size_t i = 0; i < wm->wr_cnt; i++) {
391+
struct vfio_user_region_access *in_ra;
392+
393+
/* Re-use the very similar type. */
394+
in_ra = (struct vfio_user_region_access *)&wm->wrs[i];
395+
396+
/*
397+
* We already checked total length so can be sure each entry is at least
398+
* big enough.
399+
*/
400+
if (!is_valid_region_access(vfu_ctx, sizeof(wm->wrs[i]),
401+
msg->hdr.cmd, in_ra)) {
402+
return ERROR_INT(EINVAL);
403+
}
404+
405+
if (in_ra->count == 0) {
406+
continue;
407+
}
408+
409+
buf = (char *)(&in_ra->data);
410+
411+
ret = region_access(vfu_ctx, in_ra->region, buf, in_ra->count,
412+
in_ra->offset, true);
413+
if (ret != in_ra->count) {
414+
/* FIXME we should return whatever has been accessed, not an error */
415+
if (ret >= 0) {
416+
ret = ERROR_INT(EINVAL);
417+
}
418+
return ret;
419+
}
420+
}
421+
422+
return 0;
423+
}
424+
353425
static int
354426
handle_device_get_info(vfu_ctx_t *vfu_ctx, vfu_msg_t *msg)
355427
{
@@ -1146,6 +1218,11 @@ handle_request(vfu_ctx_t *vfu_ctx, vfu_msg_t *msg)
11461218
ret = handle_region_access(vfu_ctx, msg);
11471219
break;
11481220

1221+
case VFIO_USER_REGION_WRITE_MULTI:
1222+
ret = handle_region_write_multi(vfu_ctx, msg);
1223+
break;
1224+
1225+
11491226
case VFIO_USER_DEVICE_RESET:
11501227
vfu_log(vfu_ctx, LOG_INFO, "device reset by client");
11511228
ret = handle_device_reset(vfu_ctx, VFU_RESET_DEVICE);
@@ -1334,6 +1411,10 @@ command_needs_quiesce(vfu_ctx_t *vfu_ctx, const vfu_msg_t *msg)
13341411
return true;
13351412
}
13361413
break;
1414+
1415+
case VFIO_USER_REGION_WRITE_MULTI:
1416+
/* FIXME */
1417+
return false;
13371418
}
13381419

13391420
return false;

test/py/libvfio_user.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,9 @@
158158
VFIO_USER_DMA_WRITE = 12
159159
VFIO_USER_DEVICE_RESET = 13
160160
VFIO_USER_DIRTY_PAGES = 14
161-
VFIO_USER_MAX = 15
161+
# FIXME: need tests
162+
VFIO_USER_REGION_WRITE_MULTI = 15
163+
VFIO_USER_MAX = 16
162164

163165
VFIO_USER_F_TYPE_COMMAND = 0
164166
VFIO_USER_F_TYPE_REPLY = 1

0 commit comments

Comments
 (0)