vfio queue:

* Fixed vfio-user issues reported by Coverity
 * Tweaked VFIO migration with multifd to support aarch64
 * Introduced a property to override a device PCI class code
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEoPZlSPBIlev+awtgUaNDx8/77KEFAmh2ciAACgkQUaNDx8/7
 7KErLQ/+PyyV+lGPvqNzFaNL3w9LVDiCzppPZ5dIkJ7MuwFAgonltzQS/HpoGOLW
 NMMJlDyBpilGO4pB8BGRL/Le4lZPQ+41zeCfOjG4q5cB9gYFAazj5356HOJNCsvH
 xVeBINOrwcyqa5b31UN8gRsakcJjlBv7rSDhzGPedbjek7hmfYP9Y5EBr39yx5jU
 Qw9WdI4Jxfwrz9pNkZstKNCHJDeSn8hwO4huAd6doC/Lno8rNleslALr+VdEfN7c
 SaZ+opCiNGAowzD0Whg3wnsWa/wlczkPgcQ/qa3xH0D33AGhDXCJMDdNMXeZMBra
 hjepQPPD8X6XXCBdRg7BavtxtjLAJSlghBTU5hZ+CJ/Pabyjhjh7rSmEcro2IvfL
 ++ZAakwj3tj1sBYuT0u0C5eBeieSKroInz3r7zqLPyxeYDBvD+IPySxcqgA2w3cX
 oJYgshQQHe4T4xdZKnWU2isWqkJ/X49sl7lIYCld1MgnGoZ/qEugmowsSzdnaJPG
 Rq2T8G7tk/HYDQlGbNgEsBTeHJod1ZbNw00hs1DesbJLdT4OF0d5XzxvPIHHdsHc
 9N+NCLr22gMWBi1IMqM0X8Fx5rZYKiDChW2D9onnDXUEqXT5BI+5YYefIPFQJ2xy
 fggbGXqKBfkUPoFlM8E19/dZSotgxyAS9wO3A3kx/z+J3+f24XI=
 =Ns5P
 -----END PGP SIGNATURE-----

Merge tag 'pull-vfio-20250715' of https://github.com/legoater/qemu into staging

vfio queue:

* Fixed vfio-user issues reported by Coverity
* Tweaked VFIO migration with multifd to support aarch64
* Introduced a property to override a device PCI class code

# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCAAdFiEEoPZlSPBIlev+awtgUaNDx8/77KEFAmh2ciAACgkQUaNDx8/7
# 7KErLQ/+PyyV+lGPvqNzFaNL3w9LVDiCzppPZ5dIkJ7MuwFAgonltzQS/HpoGOLW
# NMMJlDyBpilGO4pB8BGRL/Le4lZPQ+41zeCfOjG4q5cB9gYFAazj5356HOJNCsvH
# xVeBINOrwcyqa5b31UN8gRsakcJjlBv7rSDhzGPedbjek7hmfYP9Y5EBr39yx5jU
# Qw9WdI4Jxfwrz9pNkZstKNCHJDeSn8hwO4huAd6doC/Lno8rNleslALr+VdEfN7c
# SaZ+opCiNGAowzD0Whg3wnsWa/wlczkPgcQ/qa3xH0D33AGhDXCJMDdNMXeZMBra
# hjepQPPD8X6XXCBdRg7BavtxtjLAJSlghBTU5hZ+CJ/Pabyjhjh7rSmEcro2IvfL
# ++ZAakwj3tj1sBYuT0u0C5eBeieSKroInz3r7zqLPyxeYDBvD+IPySxcqgA2w3cX
# oJYgshQQHe4T4xdZKnWU2isWqkJ/X49sl7lIYCld1MgnGoZ/qEugmowsSzdnaJPG
# Rq2T8G7tk/HYDQlGbNgEsBTeHJod1ZbNw00hs1DesbJLdT4OF0d5XzxvPIHHdsHc
# 9N+NCLr22gMWBi1IMqM0X8Fx5rZYKiDChW2D9onnDXUEqXT5BI+5YYefIPFQJ2xy
# fggbGXqKBfkUPoFlM8E19/dZSotgxyAS9wO3A3kx/z+J3+f24XI=
# =Ns5P
# -----END PGP SIGNATURE-----
# gpg: Signature made Tue 15 Jul 2025 11:22:08 EDT
# gpg:                using RSA key A0F66548F04895EBFE6B0B6051A343C7CFFBECA1
# gpg: Good signature from "Cédric Le Goater <clg@redhat.com>" [full]
# gpg:                 aka "Cédric Le Goater <clg@kaod.org>" [full]
# Primary key fingerprint: A0F6 6548 F048 95EB FE6B  0B60 51A3 43C7 CFFB ECA1

* tag 'pull-vfio-20250715' of https://github.com/legoater/qemu:
  vfio/migration: Max in-flight VFIO device state buffers size limit
  vfio/migration: Add x-migration-load-config-after-iter VFIO property
  vfio/pci: Introduce x-pci-class-code option
  hw/vfio-user: fix use of uninitialized variable
  hw/vfio-user: wait for proxy close correctly
  hw/vfio: fix region fd initialization
  hw/vfio-user: add Cédric Le Goater as a maintainer

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
Stefan Hajnoczi 2025-07-16 07:07:44 -04:00
commit f79afdf7da
16 changed files with 212 additions and 21 deletions

View file

@ -4287,6 +4287,7 @@ F: tests/functional/test_multiprocess.py
VFIO-USER:
M: John Levon <john.levon@nutanix.com>
M: Thanos Makatos <thanos.makatos@nutanix.com>
M: Cédric Le Goater <clg@redhat.com>
S: Supported
F: docs/interop/vfio-user.rst
F: docs/system/devices/vfio-user.rst

View file

@ -247,3 +247,22 @@ The multifd VFIO device state transfer is controlled by
"x-migration-multifd-transfer" VFIO device property. This property defaults to
AUTO, which means that VFIO device state transfer via multifd channels is
attempted in configurations that otherwise support it.
Since the target QEMU needs to load device state buffers in-order it needs to
queue incoming buffers until they can be loaded into the device.
This means that a malicious QEMU source could theoretically cause the target
QEMU to allocate unlimited amounts of memory for such buffers-in-flight.
The "x-migration-max-queued-buffers-size" property allows capping the total size
of these VFIO device state buffers queued at the destination.
Because a malicious QEMU source causing OOM on the target is not expected to be
a realistic threat in most of VFIO live migration use cases and the right value
depends on the particular setup by default this queued buffers size limit is
disabled by setting it to UINT64_MAX.
Some host platforms (like ARM64) require that VFIO device config is loaded only
after all iterables were loaded, during non-iterables loading phase.
Such interlocking is controlled by "x-migration-load-config-after-iter" VFIO
device property, which in its default setting (AUTO) does so only on platforms
that actually require it.

View file

@ -39,6 +39,7 @@
GlobalProperty hw_compat_10_0[] = {
{ "scsi-hd", "dpofua", "off" },
{ "vfio-pci", "x-migration-load-config-after-iter", "off" },
};
const size_t hw_compat_10_0_len = G_N_ELEMENTS(hw_compat_10_0);

View file

@ -64,8 +64,6 @@ static int vfio_user_dma_unmap(const VFIOContainerBase *bcontainer,
0, &local_err)) {
error_report_err(local_err);
ret = -EFAULT;
} else {
ret = 0;
}
} else {
if (!vfio_user_send_wait(container->proxy, &msgp->hdr, NULL,
@ -92,7 +90,7 @@ static int vfio_user_dma_map(const VFIOContainerBase *bcontainer, hwaddr iova,
bcontainer);
int fd = memory_region_get_fd(mrp);
Error *local_err = NULL;
int ret;
int ret = 0;
VFIOUserFDs *fds = NULL;
VFIOUserDMAMap *msgp = g_malloc0(sizeof(*msgp));
@ -135,8 +133,6 @@ static int vfio_user_dma_map(const VFIOContainerBase *bcontainer, hwaddr iova,
0, &local_err)) {
error_report_err(local_err);
ret = -EFAULT;
} else {
ret = 0;
}
} else {
VFIOUserFDs local_fds = { 1, 0, &fd };

View file

@ -32,7 +32,6 @@ static void vfio_user_recycle(VFIOUserProxy *proxy, VFIOUserMsg *msg);
static void vfio_user_recv(void *opaque);
static void vfio_user_send(void *opaque);
static void vfio_user_cb(void *opaque);
static void vfio_user_request(void *opaque);
@ -492,7 +491,7 @@ static void vfio_user_send(void *opaque)
}
}
static void vfio_user_cb(void *opaque)
static void vfio_user_close_cb(void *opaque)
{
VFIOUserProxy *proxy = opaque;
@ -984,8 +983,11 @@ void vfio_user_disconnect(VFIOUserProxy *proxy)
* handler to run after the proxy fd handlers were
* deleted above.
*/
aio_bh_schedule_oneshot(proxy->ctx, vfio_user_cb, proxy);
qemu_cond_wait(&proxy->close_cv, &proxy->lock);
aio_bh_schedule_oneshot(proxy->ctx, vfio_user_close_cb, proxy);
while (proxy->state != VFIO_PROXY_CLOSED) {
qemu_cond_wait(&proxy->close_cv, &proxy->lock);
}
/* we now hold the only ref to proxy */
qemu_mutex_unlock(&proxy->lock);

View file

@ -463,6 +463,8 @@ void vfio_device_detach(VFIODevice *vbasedev)
void vfio_device_prepare(VFIODevice *vbasedev, VFIOContainerBase *bcontainer,
struct vfio_device_info *info)
{
int i;
vbasedev->num_irqs = info->num_irqs;
vbasedev->num_regions = info->num_regions;
vbasedev->flags = info->flags;
@ -477,6 +479,9 @@ void vfio_device_prepare(VFIODevice *vbasedev, VFIOContainerBase *bcontainer,
vbasedev->num_regions);
if (vbasedev->use_region_fds) {
vbasedev->region_fds = g_new0(int, vbasedev->num_regions);
for (i = 0; i < vbasedev->num_regions; i++) {
vbasedev->region_fds[i] = -1;
}
}
}
@ -489,7 +494,6 @@ void vfio_device_unprepare(VFIODevice *vbasedev)
if (vbasedev->region_fds != NULL && vbasedev->region_fds[i] != -1) {
close(vbasedev->region_fds[i]);
}
}
g_clear_pointer(&vbasedev->reginfo, g_free);

View file

@ -209,3 +209,20 @@ retry:
return info;
}
bool vfio_arch_wants_loading_config_after_iter(void)
{
/*
* Starting the config load only after all iterables were loaded (during
* non-iterables loading phase) is required for ARM64 due to this platform
* VFIO dependency on interrupt controller being loaded first.
*
* See commit d329f5032e17 ("vfio: Move the saving of the config space to
* the right place in VFIO migration").
*/
#if defined(TARGET_ARM)
return true;
#else
return false;
#endif
}

View file

@ -22,6 +22,7 @@
#include "migration-multifd.h"
#include "vfio-migration-internal.h"
#include "trace.h"
#include "vfio-helpers.h"
#define VFIO_DEVICE_STATE_CONFIG_STATE (1)
@ -34,6 +35,18 @@ typedef struct VFIODeviceStatePacket {
uint8_t data[0];
} QEMU_PACKED VFIODeviceStatePacket;
bool vfio_load_config_after_iter(VFIODevice *vbasedev)
{
if (vbasedev->migration_load_config_after_iter == ON_OFF_AUTO_ON) {
return true;
} else if (vbasedev->migration_load_config_after_iter == ON_OFF_AUTO_OFF) {
return false;
}
assert(vbasedev->migration_load_config_after_iter == ON_OFF_AUTO_AUTO);
return vfio_arch_wants_loading_config_after_iter();
}
/* type safety */
typedef struct VFIOStateBuffers {
GArray *array;
@ -49,12 +62,16 @@ typedef struct VFIOMultifd {
bool load_bufs_thread_running;
bool load_bufs_thread_want_exit;
bool load_bufs_iter_done;
QemuCond load_bufs_iter_done_cond;
VFIOStateBuffers load_bufs;
QemuCond load_bufs_buffer_ready_cond;
QemuCond load_bufs_thread_finished_cond;
QemuMutex load_bufs_mutex; /* Lock order: this lock -> BQL */
uint32_t load_buf_idx;
uint32_t load_buf_idx_last;
size_t load_buf_queued_pending_buffers_size;
} VFIOMultifd;
static void vfio_state_buffer_clear(gpointer data)
@ -111,6 +128,7 @@ static bool vfio_load_state_buffer_insert(VFIODevice *vbasedev,
VFIOMigration *migration = vbasedev->migration;
VFIOMultifd *multifd = migration->multifd;
VFIOStateBuffer *lb;
size_t data_size = packet_total_size - sizeof(*packet);
vfio_state_buffers_assert_init(&multifd->load_bufs);
if (packet->idx >= vfio_state_buffers_size_get(&multifd->load_bufs)) {
@ -126,8 +144,19 @@ static bool vfio_load_state_buffer_insert(VFIODevice *vbasedev,
assert(packet->idx >= multifd->load_buf_idx);
lb->data = g_memdup2(&packet->data, packet_total_size - sizeof(*packet));
lb->len = packet_total_size - sizeof(*packet);
multifd->load_buf_queued_pending_buffers_size += data_size;
if (multifd->load_buf_queued_pending_buffers_size >
vbasedev->migration_max_queued_buffers_size) {
error_setg(errp,
"%s: queuing state buffer %" PRIu32
" would exceed the size max of %" PRIu64,
vbasedev->name, packet->idx,
vbasedev->migration_max_queued_buffers_size);
return false;
}
lb->data = g_memdup2(&packet->data, data_size);
lb->len = data_size;
lb->is_present = true;
return true;
@ -311,6 +340,9 @@ static bool vfio_load_state_buffer_write(VFIODevice *vbasedev,
assert(wr_ret <= buf_len);
buf_len -= wr_ret;
buf_cur += wr_ret;
assert(multifd->load_buf_queued_pending_buffers_size >= wr_ret);
multifd->load_buf_queued_pending_buffers_size -= wr_ret;
}
trace_vfio_load_state_device_buffer_load_end(vbasedev->name,
@ -393,6 +425,22 @@ static bool vfio_load_bufs_thread(void *opaque, bool *should_quit, Error **errp)
multifd->load_buf_idx++;
}
if (vfio_load_config_after_iter(vbasedev)) {
while (!multifd->load_bufs_iter_done) {
qemu_cond_wait(&multifd->load_bufs_iter_done_cond,
&multifd->load_bufs_mutex);
/*
* Need to re-check cancellation immediately after wait in case
* cond was signalled by vfio_load_cleanup_load_bufs_thread().
*/
if (vfio_load_bufs_thread_want_exit(multifd, should_quit)) {
error_setg(errp, "operation cancelled");
goto thread_exit;
}
}
}
if (!vfio_load_bufs_thread_load_config(vbasedev, errp)) {
goto thread_exit;
}
@ -412,6 +460,48 @@ thread_exit:
return ret;
}
int vfio_load_state_config_load_ready(VFIODevice *vbasedev)
{
VFIOMigration *migration = vbasedev->migration;
VFIOMultifd *multifd = migration->multifd;
int ret = 0;
if (!vfio_multifd_transfer_enabled(vbasedev)) {
error_report("%s: got DEV_CONFIG_LOAD_READY outside multifd transfer",
vbasedev->name);
return -EINVAL;
}
if (!vfio_load_config_after_iter(vbasedev)) {
error_report("%s: got DEV_CONFIG_LOAD_READY but was disabled",
vbasedev->name);
return -EINVAL;
}
assert(multifd);
/* The lock order is load_bufs_mutex -> BQL so unlock BQL here first */
bql_unlock();
WITH_QEMU_LOCK_GUARD(&multifd->load_bufs_mutex) {
if (multifd->load_bufs_iter_done) {
/* Can't print error here as we're outside BQL */
ret = -EINVAL;
break;
}
multifd->load_bufs_iter_done = true;
qemu_cond_signal(&multifd->load_bufs_iter_done_cond);
}
bql_lock();
if (ret) {
error_report("%s: duplicate DEV_CONFIG_LOAD_READY",
vbasedev->name);
}
return ret;
}
static VFIOMultifd *vfio_multifd_new(void)
{
VFIOMultifd *multifd = g_new(VFIOMultifd, 1);
@ -422,8 +512,12 @@ static VFIOMultifd *vfio_multifd_new(void)
multifd->load_buf_idx = 0;
multifd->load_buf_idx_last = UINT32_MAX;
multifd->load_buf_queued_pending_buffers_size = 0;
qemu_cond_init(&multifd->load_bufs_buffer_ready_cond);
multifd->load_bufs_iter_done = false;
qemu_cond_init(&multifd->load_bufs_iter_done_cond);
multifd->load_bufs_thread_running = false;
multifd->load_bufs_thread_want_exit = false;
qemu_cond_init(&multifd->load_bufs_thread_finished_cond);
@ -447,6 +541,7 @@ static void vfio_load_cleanup_load_bufs_thread(VFIOMultifd *multifd)
multifd->load_bufs_thread_want_exit = true;
qemu_cond_signal(&multifd->load_bufs_buffer_ready_cond);
qemu_cond_signal(&multifd->load_bufs_iter_done_cond);
qemu_cond_wait(&multifd->load_bufs_thread_finished_cond,
&multifd->load_bufs_mutex);
}
@ -459,6 +554,7 @@ static void vfio_multifd_free(VFIOMultifd *multifd)
vfio_load_cleanup_load_bufs_thread(multifd);
qemu_cond_destroy(&multifd->load_bufs_thread_finished_cond);
qemu_cond_destroy(&multifd->load_bufs_iter_done_cond);
vfio_state_buffers_destroy(&multifd->load_bufs);
qemu_cond_destroy(&multifd->load_bufs_buffer_ready_cond);
qemu_mutex_destroy(&multifd->load_bufs_mutex);

View file

@ -20,9 +20,12 @@ void vfio_multifd_cleanup(VFIODevice *vbasedev);
bool vfio_multifd_transfer_supported(void);
bool vfio_multifd_transfer_enabled(VFIODevice *vbasedev);
bool vfio_load_config_after_iter(VFIODevice *vbasedev);
bool vfio_multifd_load_state_buffer(void *opaque, char *data, size_t data_size,
Error **errp);
int vfio_load_state_config_load_ready(VFIODevice *vbasedev);
void vfio_multifd_emit_dummy_eos(VFIODevice *vbasedev, QEMUFile *f);
bool

View file

@ -675,7 +675,11 @@ static void vfio_save_state(QEMUFile *f, void *opaque)
int ret;
if (vfio_multifd_transfer_enabled(vbasedev)) {
vfio_multifd_emit_dummy_eos(vbasedev, f);
if (vfio_load_config_after_iter(vbasedev)) {
qemu_put_be64(f, VFIO_MIG_FLAG_DEV_CONFIG_LOAD_READY);
} else {
vfio_multifd_emit_dummy_eos(vbasedev, f);
}
return;
}
@ -784,6 +788,10 @@ static int vfio_load_state(QEMUFile *f, void *opaque, int version_id)
return ret;
}
case VFIO_MIG_FLAG_DEV_CONFIG_LOAD_READY:
{
return vfio_load_state_config_load_ready(vbasedev);
}
default:
error_report("%s: Unknown tag 0x%"PRIx64, vbasedev->name, data);
return -EINVAL;

View file

@ -2893,10 +2893,6 @@ bool vfio_populate_vga(VFIOPCIDevice *vdev, Error **errp)
"vfio-vga-io@0x3c0",
QEMU_PCI_VGA_IO_HI_SIZE);
pci_register_vga(&vdev->pdev, &vdev->vga->region[QEMU_PCI_VGA_MEM].mem,
&vdev->vga->region[QEMU_PCI_VGA_IO_LO].mem,
&vdev->vga->region[QEMU_PCI_VGA_IO_HI].mem);
return true;
}
@ -3228,6 +3224,23 @@ bool vfio_pci_config_setup(VFIOPCIDevice *vdev, Error **errp)
vdev->sub_device_id);
}
/*
* Class code is a 24-bit value at config space 0x09. Allow overriding it
* with any 24-bit value.
*/
if (vdev->class_code != PCI_ANY_ID) {
if (vdev->class_code > 0xffffff) {
error_setg(errp, "invalid PCI class code provided");
return false;
}
/* Higher 24 bits of PCI_CLASS_REVISION are class code */
vfio_add_emulated_long(vdev, PCI_CLASS_REVISION,
vdev->class_code << 8, ~0xff);
trace_vfio_pci_emulated_class_code(vbasedev->name, vdev->class_code);
} else {
vdev->class_code = pci_get_long(pdev->config + PCI_CLASS_REVISION) >> 8;
}
/* QEMU can change multi-function devices to single function, or reverse */
vdev->emulated_config_bits[PCI_HEADER_TYPE] =
PCI_HEADER_TYPE_MULTI_FUNCTION;
@ -3257,6 +3270,12 @@ bool vfio_pci_config_setup(VFIOPCIDevice *vdev, Error **errp)
vfio_bars_register(vdev);
if (vdev->vga && vfio_is_vga(vdev)) {
pci_register_vga(&vdev->pdev, &vdev->vga->region[QEMU_PCI_VGA_MEM].mem,
&vdev->vga->region[QEMU_PCI_VGA_IO_LO].mem,
&vdev->vga->region[QEMU_PCI_VGA_IO_HI].mem);
}
return true;
}
@ -3623,6 +3642,11 @@ static const Property vfio_pci_dev_properties[] = {
vbasedev.migration_multifd_transfer,
vfio_pci_migration_multifd_transfer_prop, OnOffAuto,
.set_default = true, .defval.i = ON_OFF_AUTO_AUTO),
DEFINE_PROP_ON_OFF_AUTO("x-migration-load-config-after-iter", VFIOPCIDevice,
vbasedev.migration_load_config_after_iter,
ON_OFF_AUTO_AUTO),
DEFINE_PROP_SIZE("x-migration-max-queued-buffers-size", VFIOPCIDevice,
vbasedev.migration_max_queued_buffers_size, UINT64_MAX),
DEFINE_PROP_BOOL("migration-events", VFIOPCIDevice,
vbasedev.migration_events, false),
DEFINE_PROP_BOOL("x-no-mmap", VFIOPCIDevice, vbasedev.no_mmap, false),
@ -3643,6 +3667,8 @@ static const Property vfio_pci_dev_properties[] = {
sub_vendor_id, PCI_ANY_ID),
DEFINE_PROP_UINT32("x-pci-sub-device-id", VFIOPCIDevice,
sub_device_id, PCI_ANY_ID),
DEFINE_PROP_UINT32("x-pci-class-code", VFIOPCIDevice,
class_code, PCI_ANY_ID),
DEFINE_PROP_UINT32("x-igd-gms", VFIOPCIDevice, igd_gms, 0),
DEFINE_PROP_UNSIGNED_NODEFAULT("x-nv-gpudirect-clique", VFIOPCIDevice,
nv_gpudirect_clique,
@ -3797,6 +3823,20 @@ static void vfio_pci_dev_class_init(ObjectClass *klass, const void *data)
"x-migration-multifd-transfer",
"Transfer this device state via "
"multifd channels when live migrating it");
object_class_property_set_description(klass, /* 10.1 */
"x-migration-load-config-after-iter",
"Start the config load only after "
"all iterables were loaded (during "
"non-iterables loading phase) when "
"doing live migration of device state "
"via multifd channels");
object_class_property_set_description(klass, /* 10.1 */
"x-migration-max-queued-buffers-size",
"Maximum size of in-flight VFIO "
"device state buffers queued at the "
"destination when doing live "
"migration of device state via "
"multifd channels");
}
static const TypeInfo vfio_pci_dev_info = {

View file

@ -157,6 +157,7 @@ struct VFIOPCIDevice {
uint32_t device_id;
uint32_t sub_vendor_id;
uint32_t sub_device_id;
uint32_t class_code;
uint32_t features;
#define VFIO_FEATURE_ENABLE_VGA_BIT 0
#define VFIO_FEATURE_ENABLE_VGA (1 << VFIO_FEATURE_ENABLE_VGA_BIT)
@ -205,10 +206,7 @@ static inline bool vfio_pci_is(VFIOPCIDevice *vdev, uint32_t vendor, uint32_t de
static inline bool vfio_is_vga(VFIOPCIDevice *vdev)
{
PCIDevice *pdev = &vdev->pdev;
uint16_t class = pci_get_word(pdev->config + PCI_CLASS_DEVICE);
return class == PCI_CLASS_DISPLAY_VGA;
return (vdev->class_code >> 8) == PCI_CLASS_DISPLAY_VGA;
}
/* MSI/MSI-X/INTx */

View file

@ -48,6 +48,7 @@ vfio_pci_emulated_vendor_id(const char *name, uint16_t val) "%s 0x%04x"
vfio_pci_emulated_device_id(const char *name, uint16_t val) "%s 0x%04x"
vfio_pci_emulated_sub_vendor_id(const char *name, uint16_t val) "%s 0x%04x"
vfio_pci_emulated_sub_device_id(const char *name, uint16_t val) "%s 0x%04x"
vfio_pci_emulated_class_code(const char *name, uint32_t val) "%s 0x%06x"
# pci-quirks.c
vfio_quirk_rom_in_denylist(const char *name, uint16_t vid, uint16_t did) "%s %04x:%04x"

View file

@ -32,4 +32,6 @@ struct vfio_device_info *vfio_get_device_info(int fd);
int vfio_kvm_device_add_fd(int fd, Error **errp);
int vfio_kvm_device_del_fd(int fd, Error **errp);
bool vfio_arch_wants_loading_config_after_iter(void);
#endif /* HW_VFIO_VFIO_HELPERS_H */

View file

@ -32,6 +32,7 @@
#define VFIO_MIG_FLAG_DEV_SETUP_STATE (0xffffffffef100003ULL)
#define VFIO_MIG_FLAG_DEV_DATA_STATE (0xffffffffef100004ULL)
#define VFIO_MIG_FLAG_DEV_INIT_DATA_SENT (0xffffffffef100005ULL)
#define VFIO_MIG_FLAG_DEV_CONFIG_LOAD_READY (0xffffffffef100006ULL)
typedef struct VFIODevice VFIODevice;
typedef struct VFIOMultifd VFIOMultifd;

View file

@ -67,6 +67,8 @@ typedef struct VFIODevice {
bool ram_block_discard_allowed;
OnOffAuto enable_migration;
OnOffAuto migration_multifd_transfer;
OnOffAuto migration_load_config_after_iter;
uint64_t migration_max_queued_buffers_size;
bool migration_events;
bool use_region_fds;
VFIODeviceOps *ops;