@@ -264,10 +264,27 @@ is_valid_region_access(vfu_ctx_t *vfu_ctx, size_t size, uint16_t cmd,
264
264
return false;
265
265
}
266
266
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 ;
271
288
}
272
289
273
290
index = ra -> region ;
@@ -350,6 +367,61 @@ handle_region_access(vfu_ctx_t *vfu_ctx, vfu_msg_t *msg)
350
367
return 0 ;
351
368
}
352
369
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
+
353
425
static int
354
426
handle_device_get_info (vfu_ctx_t * vfu_ctx , vfu_msg_t * msg )
355
427
{
@@ -1146,6 +1218,11 @@ handle_request(vfu_ctx_t *vfu_ctx, vfu_msg_t *msg)
1146
1218
ret = handle_region_access (vfu_ctx , msg );
1147
1219
break ;
1148
1220
1221
+ case VFIO_USER_REGION_WRITE_MULTI :
1222
+ ret = handle_region_write_multi (vfu_ctx , msg );
1223
+ break ;
1224
+
1225
+
1149
1226
case VFIO_USER_DEVICE_RESET :
1150
1227
vfu_log (vfu_ctx , LOG_INFO , "device reset by client" );
1151
1228
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)
1334
1411
return true;
1335
1412
}
1336
1413
break ;
1414
+
1415
+ case VFIO_USER_REGION_WRITE_MULTI :
1416
+ /* FIXME */
1417
+ return false;
1337
1418
}
1338
1419
1339
1420
return false;
0 commit comments