Move the config size calculation from virtio_net_init() to virtio_common_init() so that all virtio devices can benefit. This requires that the host_features be passed to virtio_common_init(), and the size of the config struct will be calculated based on which feature bits are enabled. This calculation is performed using a per-driver table that maps each feature bit to the size of the config struct at the time that the feature was introduced. virtio_common_init() also takes a minimum config size to use in the case that all feature bits are disabled.
For now, each driver contains a dummy table that uses the full size of the config struct. These dummy tables will be replaced on a per-driver basis. Signed-off-by: Jesse Larrew <jlar...@linux.vnet.ibm.com> --- hw/9pfs/virtio-9p-device.c | 15 ++++++++++----- hw/virtio-balloon.c | 15 ++++++++++++--- hw/virtio-blk.c | 14 +++++++++++--- hw/virtio-net.c | 11 +++-------- hw/virtio-rng.c | 8 +++++++- hw/virtio-scsi.c | 10 +++++++++- hw/virtio-serial-bus.c | 13 ++++++++++--- hw/virtio.c | 13 ++++++++++++- hw/virtio.h | 4 +++- 9 files changed, 77 insertions(+), 26 deletions(-) diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c index 74155fb..24d033b 100644 --- a/hw/9pfs/virtio-9p-device.c +++ b/hw/9pfs/virtio-9p-device.c @@ -20,6 +20,12 @@ #include "virtio-9p-xattr.h" #include "virtio-9p-coth.h" +static VirtIOFeature feature_sizes[] = { + {.flags = 0xffffffff, /* dummy table -- all features included. */ + .end = endof(struct virtio_9p_config, tag) + MAX_TAG_LEN}, + {} +}; + static uint32_t virtio_9p_get_features(VirtIODevice *vdev, uint32_t features) { features |= 1 << VIRTIO_9P_MOUNT_TAG; @@ -54,11 +60,10 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf) FsDriverEntry *fse; V9fsPath path; - s = (V9fsState *)virtio_common_init("virtio-9p", - VIRTIO_ID_9P, - sizeof(struct virtio_9p_config)+ - MAX_TAG_LEN, - sizeof(V9fsState)); + s = (V9fsState *)virtio_common_init("virtio-9p", VIRTIO_ID_9P, + host_features, feature_sizes, + sizeof(struct virtio_9p_config) + + MAX_TAG_LEN, sizeof(V9fsState)); /* initialize pdu allocator */ QLIST_INIT(&s->free_list); QLIST_INIT(&s->active_list); diff --git a/hw/virtio-balloon.c b/hw/virtio-balloon.c index 4574db6..81f27e9 100644 --- a/hw/virtio-balloon.c +++ b/hw/virtio-balloon.c @@ -29,6 +29,12 @@ #include <sys/mman.h> #endif +static VirtIOFeature feature_sizes[] = { + {.flags = 0xffffffff, /* dummy table -- all features included. */ + .end = sizeof(struct virtio_balloon_config)}, + {} +}; + typedef struct VirtIOBalloon { VirtIODevice vdev; @@ -278,7 +284,7 @@ static void virtio_balloon_get_config(VirtIODevice *vdev, uint8_t *config_data) config.num_pages = cpu_to_le32(dev->num_pages); config.actual = cpu_to_le32(dev->actual); - memcpy(config_data, &config, 8); + memcpy(config_data, &config, vdev->config_len); } static void virtio_balloon_set_config(VirtIODevice *vdev, @@ -287,7 +293,7 @@ static void virtio_balloon_set_config(VirtIODevice *vdev, VirtIOBalloon *dev = to_virtio_balloon(vdev); struct virtio_balloon_config config; uint32_t oldactual = dev->actual; - memcpy(&config, config_data, 8); + memcpy(&config, config_data, vdev->config_len); dev->actual = le32_to_cpu(config.actual); if (dev->actual != oldactual) { qemu_balloon_changed(ram_size - @@ -356,7 +362,10 @@ VirtIODevice *virtio_balloon_init(DeviceState *dev, uint32_t host_features) s = (VirtIOBalloon *)virtio_common_init("virtio-balloon", VIRTIO_ID_BALLOON, - 8, sizeof(VirtIOBalloon)); + host_features, feature_sizes, + endof(struct virtio_balloon_config, + actual), + sizeof(VirtIOBalloon)); s->vdev.get_config = virtio_balloon_get_config; s->vdev.set_config = virtio_balloon_set_config; diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c index b3ab267..788a4c7 100644 --- a/hw/virtio-blk.c +++ b/hw/virtio-blk.c @@ -25,6 +25,12 @@ # include <scsi/sg.h> #endif +static VirtIOFeature feature_sizes[] = { + {.flags = 0xffffffff, /* dummy table -- all features included */ + .end = sizeof(struct virtio_blk_config)}, + {} +}; + typedef struct VirtIOBlock { VirtIODevice vdev; @@ -531,7 +537,7 @@ static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config) blkcfg.physical_block_exp = get_physical_block_exp(s->conf); blkcfg.alignment_offset = 0; blkcfg.wce = bdrv_enable_write_cache(s->bs); - memcpy(config, &blkcfg, sizeof(struct virtio_blk_config)); + memcpy(config, &blkcfg, vdev->config_len); } static void virtio_blk_set_config(VirtIODevice *vdev, const uint8_t *config) @@ -539,7 +545,7 @@ static void virtio_blk_set_config(VirtIODevice *vdev, const uint8_t *config) VirtIOBlock *s = to_virtio_blk(vdev); struct virtio_blk_config blkcfg; - memcpy(&blkcfg, config, sizeof(blkcfg)); + memcpy(&blkcfg, config, vdev->config_len); bdrv_set_enable_write_cache(s->bs, blkcfg.wce != 0); } @@ -660,7 +666,9 @@ VirtIODevice *virtio_blk_init(DeviceState *dev, VirtIOBlkConf *blk, } s = (VirtIOBlock *)virtio_common_init("virtio-blk", VIRTIO_ID_BLOCK, - sizeof(struct virtio_blk_config), + host_features, feature_sizes, + endof(struct virtio_blk_config, + blk_size), sizeof(VirtIOBlock)); s->vdev.get_config = virtio_blk_update_config; diff --git a/hw/virtio-net.c b/hw/virtio-net.c index 78dc97d..302e93b 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -1292,16 +1292,11 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf, virtio_net_conf *net, uint32_t host_features) { VirtIONet *n; - int i, config_size = 0; - - for (i = 0; feature_sizes[i].flags != 0; i++) { - if (host_features & feature_sizes[i].flags) { - config_size = MAX(feature_sizes[i].end, config_size); - } - } + int i; n = (VirtIONet *)virtio_common_init("virtio-net", VIRTIO_ID_NET, - config_size, sizeof(VirtIONet)); + host_features, feature_sizes, 0, + sizeof(VirtIONet)); n->vdev.get_config = virtio_net_get_config; n->vdev.set_config = virtio_net_set_config; diff --git a/hw/virtio-rng.c b/hw/virtio-rng.c index e063127..c53cc08 100644 --- a/hw/virtio-rng.c +++ b/hw/virtio-rng.c @@ -15,6 +15,12 @@ #include "virtio-rng.h" #include "qemu/rng.h" +static VirtIOFeature feature_sizes[] = { + {.flags = 0xffffffff, /* dummy table -- all features included. */ + .end = endof(struct VirtIORNGConf, default_backend)}, + {} +}; + typedef struct VirtIORNG { VirtIODevice vdev; @@ -155,7 +161,7 @@ VirtIODevice *virtio_rng_init(DeviceState *dev, VirtIORNGConf *conf) VirtIODevice *vdev; Error *local_err = NULL; - vdev = virtio_common_init("virtio-rng", VIRTIO_ID_RNG, 0, + vdev = virtio_common_init("virtio-rng", VIRTIO_ID_RNG, 0, feature_sizes, 0, sizeof(VirtIORNG)); vrng = DO_UPCAST(VirtIORNG, vdev, vdev); diff --git a/hw/virtio-scsi.c b/hw/virtio-scsi.c index d6db042..6c92975 100644 --- a/hw/virtio-scsi.c +++ b/hw/virtio-scsi.c @@ -17,6 +17,12 @@ #include <hw/scsi.h> #include <hw/scsi-defs.h> +static VirtIOFeature feature_sizes[] = { + {.flags = 0xffffffff, + .end = sizeof(struct VirtIOSCSIConf)}, + {} +}; + #define VIRTIO_SCSI_VQ_SIZE 128 #define VIRTIO_SCSI_CDB_SIZE 32 #define VIRTIO_SCSI_SENSE_SIZE 96 @@ -710,7 +716,9 @@ VirtIODevice *virtio_scsi_init(DeviceState *dev, VirtIOSCSIConf *proxyconf, sz = sizeof(VirtIOSCSI) + proxyconf->num_queues * sizeof(VirtQueue *); s = (VirtIOSCSI *)virtio_common_init("virtio-scsi", VIRTIO_ID_SCSI, - sizeof(VirtIOSCSIConfig), sz); + host_features, feature_sizes, + endof(struct VirtIOSCSIConf, + cmd_per_lun), sz); s->qdev = dev; s->conf = proxyconf; diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c index d6b588f..9cd9fbd 100644 --- a/hw/virtio-serial-bus.c +++ b/hw/virtio-serial-bus.c @@ -25,6 +25,12 @@ #include "trace.h" #include "virtio-serial.h" +static VirtIOFeature feature_sizes[] = { + {.flags = 0xffffffff, /* dummy table -- all features included. */ + .end = sizeof(struct virtio_console_config)}, + {} +}; + /* The virtio-serial bus on top of which the ports will ride as devices */ struct VirtIOSerialBus { BusState qbus; @@ -523,14 +529,14 @@ static void get_config(VirtIODevice *vdev, uint8_t *config_data) VirtIOSerial *vser; vser = DO_UPCAST(VirtIOSerial, vdev, vdev); - memcpy(config_data, &vser->config, sizeof(struct virtio_console_config)); + memcpy(config_data, &vser->config, vdev->config_len); } static void set_config(VirtIODevice *vdev, const uint8_t *config_data) { struct virtio_console_config config; - memcpy(&config, config_data, sizeof(config)); + memcpy(&config, config_data, vdev->config_len); } static void guest_reset(VirtIOSerial *vser) @@ -964,7 +970,8 @@ VirtIODevice *virtio_serial_init(DeviceState *dev, virtio_serial_conf *conf, } vdev = virtio_common_init("virtio-serial", VIRTIO_ID_CONSOLE, - sizeof(struct virtio_console_config), + host_features, feature_sizes, + endof(struct virtio_console_config, rows), sizeof(VirtIOSerial)); vser = DO_UPCAST(VirtIOSerial, vdev, vdev); diff --git a/hw/virtio.c b/hw/virtio.c index e259348..487fdab 100644 --- a/hw/virtio.c +++ b/hw/virtio.c @@ -948,10 +948,21 @@ void virtio_init(VirtIODevice *vdev, const char *name, } VirtIODevice *virtio_common_init(const char *name, uint16_t device_id, - size_t config_size, size_t struct_size) + uint32_t host_features, + const VirtIOFeature *feature_table, + size_t min_config_size, size_t struct_size) { + int i, config_size = min_config_size; VirtIODevice *vdev; + vdev = g_malloc0(struct_size); + + for (i = 0; feature_table && feature_table[i].flags != 0; i++) { + if (host_features & feature_table[i].flags) { + config_size = MAX(feature_table[i].end, config_size); + } + } + virtio_init(vdev, name, device_id, config_size); return vdev; } diff --git a/hw/virtio.h b/hw/virtio.h index 17ce9c8..f3b7e28 100644 --- a/hw/virtio.h +++ b/hw/virtio.h @@ -229,7 +229,9 @@ int virtio_queue_empty(VirtQueue *vq); /* Host binding interface. */ VirtIODevice *virtio_common_init(const char *name, uint16_t device_id, - size_t config_size, size_t struct_size); + uint32_t host_features, + const VirtIOFeature *feature_table, + size_t min_config_size, size_t struct_size); uint32_t virtio_config_readb(VirtIODevice *vdev, uint32_t addr); uint32_t virtio_config_readw(VirtIODevice *vdev, uint32_t addr); uint32_t virtio_config_readl(VirtIODevice *vdev, uint32_t addr); -- 1.7.11.7