aboutsummaryrefslogtreecommitdiff
path: root/hw/virtio
diff options
context:
space:
mode:
Diffstat (limited to 'hw/virtio')
-rw-r--r--hw/virtio/trace-events2
-rw-r--r--hw/virtio/vhost-user.c34
-rw-r--r--hw/virtio/vhost.c1
-rw-r--r--hw/virtio/virtio-balloon.c7
-rw-r--r--hw/virtio/virtio-bus.c8
-rw-r--r--hw/virtio/virtio-crypto-pci.c6
-rw-r--r--hw/virtio/virtio-crypto.c41
-rw-r--r--hw/virtio/virtio-pci.c21
-rw-r--r--hw/virtio/virtio-pci.h4
-rw-r--r--hw/virtio/virtio.c108
10 files changed, 200 insertions, 32 deletions
diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events
index 7b6f55e..6926eed 100644
--- a/hw/virtio/trace-events
+++ b/hw/virtio/trace-events
@@ -15,6 +15,8 @@ virtio_rng_pushed(void *rng, size_t len) "rng %p: %zd bytes pushed"
virtio_rng_request(void *rng, size_t size, unsigned quota) "rng %p: %zd bytes requested, %u bytes quota left"
# hw/virtio/virtio-balloon.c
+#
+virtio_balloon_bad_addr(uint64_t gpa) "%"PRIx64
virtio_balloon_handle_output(const char *name, uint64_t gpa) "section name: %s gpa: %"PRIx64
virtio_balloon_get_config(uint32_t num_pages, uint32_t actual) "num_pages: %d actual: %d"
virtio_balloon_set_config(uint32_t actual, uint32_t oldactual) "actual: %d oldactual: %d"
diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index 7ee92b3..9334a8a 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -32,6 +32,7 @@ enum VhostUserProtocolFeature {
VHOST_USER_PROTOCOL_F_LOG_SHMFD = 1,
VHOST_USER_PROTOCOL_F_RARP = 2,
VHOST_USER_PROTOCOL_F_REPLY_ACK = 3,
+ VHOST_USER_PROTOCOL_F_NET_MTU = 4,
VHOST_USER_PROTOCOL_F_MAX
};
@@ -59,6 +60,7 @@ typedef enum VhostUserRequest {
VHOST_USER_GET_QUEUE_NUM = 17,
VHOST_USER_SET_VRING_ENABLE = 18,
VHOST_USER_SEND_RARP = 19,
+ VHOST_USER_NET_SET_MTU = 20,
VHOST_USER_MAX
} VhostUserRequest;
@@ -186,6 +188,7 @@ static bool vhost_user_one_time_request(VhostUserRequest request)
case VHOST_USER_RESET_OWNER:
case VHOST_USER_SET_MEM_TABLE:
case VHOST_USER_GET_QUEUE_NUM:
+ case VHOST_USER_NET_SET_MTU:
return true;
default:
return false;
@@ -685,6 +688,36 @@ static bool vhost_user_can_merge(struct vhost_dev *dev,
return mfd == rfd;
}
+static int vhost_user_net_set_mtu(struct vhost_dev *dev, uint16_t mtu)
+{
+ VhostUserMsg msg;
+ bool reply_supported = virtio_has_feature(dev->protocol_features,
+ VHOST_USER_PROTOCOL_F_REPLY_ACK);
+
+ if (!(dev->protocol_features & (1ULL << VHOST_USER_PROTOCOL_F_NET_MTU))) {
+ return 0;
+ }
+
+ msg.request = VHOST_USER_NET_SET_MTU;
+ msg.payload.u64 = mtu;
+ msg.size = sizeof(msg.payload.u64);
+ msg.flags = VHOST_USER_VERSION;
+ if (reply_supported) {
+ msg.flags |= VHOST_USER_NEED_REPLY_MASK;
+ }
+
+ if (vhost_user_write(dev, &msg, NULL, 0) < 0) {
+ return -1;
+ }
+
+ /* If reply_ack supported, slave has to ack specified MTU is valid */
+ if (reply_supported) {
+ return process_message_reply(dev, msg.request);
+ }
+
+ return 0;
+}
+
const VhostOps user_ops = {
.backend_type = VHOST_BACKEND_TYPE_USER,
.vhost_backend_init = vhost_user_init,
@@ -708,4 +741,5 @@ const VhostOps user_ops = {
.vhost_requires_shm_log = vhost_user_requires_shm_log,
.vhost_migration_done = vhost_user_migration_done,
.vhost_backend_can_merge = vhost_user_can_merge,
+ .vhost_net_set_mtu = vhost_user_net_set_mtu,
};
diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index f7f7023..d396b22 100644
--- a/hw/virtio/vhost.c
+++ b/hw/virtio/vhost.c
@@ -993,6 +993,7 @@ static void vhost_virtqueue_stop(struct vhost_dev *dev,
virtio_queue_set_last_avail_idx(vdev, idx, state.num);
}
virtio_queue_invalidate_signalled_used(vdev, idx);
+ virtio_queue_update_used_idx(vdev, idx);
/* In the cross-endian case, we need to reset the vring endianness to
* native as legacy devices expect so by default.
diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c
index 884570a..a705e0e 100644
--- a/hw/virtio/virtio-balloon.c
+++ b/hw/virtio/virtio-balloon.c
@@ -228,8 +228,13 @@ static void virtio_balloon_handle_output(VirtIODevice *vdev, VirtQueue *vq)
/* FIXME: remove get_system_memory(), but how? */
section = memory_region_find(get_system_memory(), pa, 1);
- if (!int128_nz(section.size) || !memory_region_is_ram(section.mr))
+ if (!int128_nz(section.size) ||
+ !memory_region_is_ram(section.mr) ||
+ memory_region_is_rom(section.mr) ||
+ memory_region_is_romd(section.mr)) {
+ trace_virtio_balloon_bad_addr(pa);
continue;
+ }
trace_virtio_balloon_handle_output(memory_region_name(section.mr),
pa);
diff --git a/hw/virtio/virtio-bus.c b/hw/virtio/virtio-bus.c
index d6c0c72..d31cc00 100644
--- a/hw/virtio/virtio-bus.c
+++ b/hw/virtio/virtio-bus.c
@@ -28,6 +28,7 @@
#include "hw/qdev.h"
#include "hw/virtio/virtio-bus.h"
#include "hw/virtio/virtio.h"
+#include "exec/address-spaces.h"
/* #define DEBUG_VIRTIO_BUS */
@@ -61,6 +62,13 @@ void virtio_bus_device_plugged(VirtIODevice *vdev, Error **errp)
if (klass->device_plugged != NULL) {
klass->device_plugged(qbus->parent, errp);
}
+
+ if (klass->get_dma_as != NULL &&
+ virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM)) {
+ vdev->dma_as = klass->get_dma_as(qbus->parent);
+ } else {
+ vdev->dma_as = &address_space_memory;
+ }
}
/* Reset the virtio_bus */
diff --git a/hw/virtio/virtio-crypto-pci.c b/hw/virtio/virtio-crypto-pci.c
index a1b0906..422aca3 100644
--- a/hw/virtio/virtio-crypto-pci.c
+++ b/hw/virtio/virtio-crypto-pci.c
@@ -31,6 +31,11 @@ static void virtio_crypto_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
VirtIOCryptoPCI *vcrypto = VIRTIO_CRYPTO_PCI(vpci_dev);
DeviceState *vdev = DEVICE(&vcrypto->vdev);
+ if (vcrypto->vdev.conf.cryptodev == NULL) {
+ error_setg(errp, "'cryptodev' parameter expects a valid object");
+ return;
+ }
+
qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
virtio_pci_force_virtio_1(vpci_dev);
object_property_set_bool(OBJECT(vdev), true, "realized", errp);
@@ -48,7 +53,6 @@ static void virtio_crypto_pci_class_init(ObjectClass *klass, void *data)
k->realize = virtio_crypto_pci_realize;
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
dc->props = virtio_crypto_pci_properties;
- dc->hotpluggable = false;
pcidev_k->class_id = PCI_CLASS_OTHERS;
}
diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c
index 2f2467e..296472f 100644
--- a/hw/virtio/virtio-crypto.c
+++ b/hw/virtio/virtio-crypto.c
@@ -337,7 +337,18 @@ static void virtio_crypto_free_request(VirtIOCryptoReq *req)
{
if (req) {
if (req->flags == CRYPTODEV_BACKEND_ALG_SYM) {
- g_free(req->u.sym_op_info);
+ size_t max_len;
+ CryptoDevBackendSymOpInfo *op_info = req->u.sym_op_info;
+
+ max_len = op_info->iv_len +
+ op_info->aad_len +
+ op_info->src_len +
+ op_info->dst_len +
+ op_info->digest_result_len;
+
+ /* Zeroize and free request data structure */
+ memset(op_info, 0, sizeof(*op_info) + max_len);
+ g_free(op_info);
}
g_free(req);
}
@@ -355,7 +366,7 @@ virtio_crypto_sym_input_data_helper(VirtIODevice *vdev,
return;
}
- len = sym_op_info->dst_len;
+ len = sym_op_info->src_len;
/* Save the cipher result */
s = iov_from_buf(req->in_iov, req->in_num, 0, sym_op_info->dst, len);
if (s != len) {
@@ -416,7 +427,7 @@ virtio_crypto_sym_op_helper(VirtIODevice *vdev,
uint32_t hash_start_src_offset = 0, len_to_hash = 0;
uint32_t cipher_start_src_offset = 0, len_to_cipher = 0;
- size_t max_len, curr_size = 0;
+ uint64_t max_len, curr_size = 0;
size_t s;
/* Plain cipher */
@@ -441,7 +452,7 @@ virtio_crypto_sym_op_helper(VirtIODevice *vdev,
return NULL;
}
- max_len = iv_len + aad_len + src_len + dst_len + hash_result_len;
+ max_len = (uint64_t)iv_len + aad_len + src_len + dst_len + hash_result_len;
if (unlikely(max_len > vcrypto->conf.max_size)) {
virtio_error(vdev, "virtio-crypto too big length");
return NULL;
@@ -732,7 +743,7 @@ static void virtio_crypto_reset(VirtIODevice *vdev)
VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(vdev);
/* multiqueue is disabled by default */
vcrypto->curr_queues = 1;
- if (!vcrypto->cryptodev->ready) {
+ if (!cryptodev_backend_is_ready(vcrypto->cryptodev)) {
vcrypto->status &= ~VIRTIO_CRYPTO_S_HW_READY;
} else {
vcrypto->status |= VIRTIO_CRYPTO_S_HW_READY;
@@ -792,13 +803,14 @@ static void virtio_crypto_device_realize(DeviceState *dev, Error **errp)
}
vcrypto->ctrl_vq = virtio_add_queue(vdev, 64, virtio_crypto_handle_ctrl);
- if (!vcrypto->cryptodev->ready) {
+ if (!cryptodev_backend_is_ready(vcrypto->cryptodev)) {
vcrypto->status &= ~VIRTIO_CRYPTO_S_HW_READY;
} else {
vcrypto->status |= VIRTIO_CRYPTO_S_HW_READY;
}
virtio_crypto_init_config(vdev);
+ cryptodev_backend_set_used(vcrypto->cryptodev, true);
}
static void virtio_crypto_device_unrealize(DeviceState *dev, Error **errp)
@@ -818,6 +830,7 @@ static void virtio_crypto_device_unrealize(DeviceState *dev, Error **errp)
g_free(vcrypto->vqs);
virtio_cleanup(vdev);
+ cryptodev_backend_set_used(vcrypto->cryptodev, false);
}
static const VMStateDescription vmstate_virtio_crypto = {
@@ -875,6 +888,20 @@ static void virtio_crypto_class_init(ObjectClass *klass, void *data)
vdc->reset = virtio_crypto_reset;
}
+static void
+virtio_crypto_check_cryptodev_is_used(Object *obj, const char *name,
+ Object *val, Error **errp)
+{
+ if (cryptodev_backend_is_used(CRYPTODEV_BACKEND(val))) {
+ char *path = object_get_canonical_path_component(val);
+ error_setg(errp,
+ "can't use already used cryptodev backend: %s", path);
+ g_free(path);
+ } else {
+ qdev_prop_allow_set_link_before_realize(obj, name, val, errp);
+ }
+}
+
static void virtio_crypto_instance_init(Object *obj)
{
VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(obj);
@@ -888,7 +915,7 @@ static void virtio_crypto_instance_init(Object *obj)
object_property_add_link(obj, "cryptodev",
TYPE_CRYPTODEV_BACKEND,
(Object **)&vcrypto->conf.cryptodev,
- qdev_prop_allow_set_link_before_realize,
+ virtio_crypto_check_cryptodev_is_used,
OBJ_PROP_LINK_UNREF_ON_RELEASE, NULL);
}
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index 21c2b9d..854b8f2 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -1144,6 +1144,14 @@ static int virtio_pci_query_nvectors(DeviceState *d)
return proxy->nvectors;
}
+static AddressSpace *virtio_pci_get_dma_as(DeviceState *d)
+{
+ VirtIOPCIProxy *proxy = VIRTIO_PCI(d);
+ PCIDevice *dev = &proxy->pci_dev;
+
+ return pci_get_address_space(dev);
+}
+
static int virtio_pci_add_mem_cap(VirtIOPCIProxy *proxy,
struct virtio_pci_cap *cap)
{
@@ -1601,6 +1609,11 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp)
}
if (legacy) {
+ if (virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM)) {
+ error_setg(errp, "VIRTIO_F_IOMMU_PLATFORM was supported by"
+ "neither legacy nor transitional device.");
+ return ;
+ }
/* legacy and transitional */
pci_set_word(config + PCI_SUBSYSTEM_VENDOR_ID,
pci_get_word(config + PCI_VENDOR_ID));
@@ -1802,6 +1815,11 @@ static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp)
* PCI Power Management Interface Specification.
*/
pci_set_word(pci_dev->config + pos + PCI_PM_PMC, 0x3);
+
+ if (proxy->flags & VIRTIO_PCI_FLAG_ATS) {
+ pcie_ats_init(pci_dev, 256);
+ }
+
} else {
/*
* make future invocations of pci_is_express() return false
@@ -1855,6 +1873,8 @@ static Property virtio_pci_properties[] = {
VIRTIO_PCI_FLAG_PAGE_PER_VQ_BIT, false),
DEFINE_PROP_BOOL("x-ignore-backend-features", VirtIOPCIProxy,
ignore_backend_features, false),
+ DEFINE_PROP_BIT("ats", VirtIOPCIProxy, flags,
+ VIRTIO_PCI_FLAG_ATS_BIT, false),
DEFINE_PROP_END_OF_LIST(),
};
@@ -2520,6 +2540,7 @@ static void virtio_pci_bus_class_init(ObjectClass *klass, void *data)
k->query_nvectors = virtio_pci_query_nvectors;
k->ioeventfd_enabled = virtio_pci_ioeventfd_enabled;
k->ioeventfd_assign = virtio_pci_ioeventfd_assign;
+ k->get_dma_as = virtio_pci_get_dma_as;
}
static const TypeInfo virtio_pci_bus_info = {
diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h
index 5e07886..d00064c 100644
--- a/hw/virtio/virtio-pci.h
+++ b/hw/virtio/virtio-pci.h
@@ -72,6 +72,7 @@ enum {
VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY_BIT,
VIRTIO_PCI_FLAG_DISABLE_PCIE_BIT,
VIRTIO_PCI_FLAG_PAGE_PER_VQ_BIT,
+ VIRTIO_PCI_FLAG_ATS_BIT,
};
/* Need to activate work-arounds for buggy guests at vmstate load. */
@@ -96,6 +97,9 @@ enum {
#define VIRTIO_PCI_FLAG_PAGE_PER_VQ \
(1 << VIRTIO_PCI_FLAG_PAGE_PER_VQ_BIT)
+/* address space translation service */
+#define VIRTIO_PCI_FLAG_ATS (1 << VIRTIO_PCI_FLAG_ATS_BIT)
+
typedef struct {
MSIMessage msg;
int virq;
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index d40711a..aa4f38f 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -23,6 +23,7 @@
#include "hw/virtio/virtio-bus.h"
#include "migration/migration.h"
#include "hw/virtio/virtio-access.h"
+#include "sysemu/dma.h"
/*
* The alignment to use between consumer and producer parts of vring.
@@ -92,7 +93,7 @@ struct VirtQueue
uint16_t queue_index;
- int inuse;
+ unsigned int inuse;
uint16_t vector;
VirtIOHandleOutput handle_output;
@@ -121,7 +122,7 @@ void virtio_queue_update_rings(VirtIODevice *vdev, int n)
static void vring_desc_read(VirtIODevice *vdev, VRingDesc *desc,
hwaddr desc_pa, int i)
{
- address_space_read(&address_space_memory, desc_pa + i * sizeof(VRingDesc),
+ address_space_read(vdev->dma_as, desc_pa + i * sizeof(VRingDesc),
MEMTXATTRS_UNSPECIFIED, (void *)desc, sizeof(VRingDesc));
virtio_tswap64s(vdev, &desc->addr);
virtio_tswap32s(vdev, &desc->len);
@@ -163,7 +164,7 @@ static inline void vring_used_write(VirtQueue *vq, VRingUsedElem *uelem,
virtio_tswap32s(vq->vdev, &uelem->id);
virtio_tswap32s(vq->vdev, &uelem->len);
pa = vq->vring.used + offsetof(VRingUsed, ring[i]);
- address_space_write(&address_space_memory, pa, MEMTXATTRS_UNSPECIFIED,
+ address_space_write(vq->vdev->dma_as, pa, MEMTXATTRS_UNSPECIFIED,
(void *)uelem, sizeof(VRingUsedElem));
}
@@ -249,6 +250,7 @@ int virtio_queue_empty(VirtQueue *vq)
static void virtqueue_unmap_sg(VirtQueue *vq, const VirtQueueElement *elem,
unsigned int len)
{
+ AddressSpace *dma_as = vq->vdev->dma_as;
unsigned int offset;
int i;
@@ -256,17 +258,18 @@ static void virtqueue_unmap_sg(VirtQueue *vq, const VirtQueueElement *elem,
for (i = 0; i < elem->in_num; i++) {
size_t size = MIN(len - offset, elem->in_sg[i].iov_len);
- cpu_physical_memory_unmap(elem->in_sg[i].iov_base,
- elem->in_sg[i].iov_len,
- 1, size);
+ dma_memory_unmap(dma_as, elem->in_sg[i].iov_base,
+ elem->in_sg[i].iov_len,
+ DMA_DIRECTION_FROM_DEVICE, size);
offset += size;
}
for (i = 0; i < elem->out_num; i++)
- cpu_physical_memory_unmap(elem->out_sg[i].iov_base,
- elem->out_sg[i].iov_len,
- 0, elem->out_sg[i].iov_len);
+ dma_memory_unmap(dma_as, elem->out_sg[i].iov_base,
+ elem->out_sg[i].iov_len,
+ DMA_DIRECTION_TO_DEVICE,
+ elem->out_sg[i].iov_len);
}
/* virtqueue_detach_element:
@@ -560,7 +563,10 @@ static bool virtqueue_map_desc(VirtIODevice *vdev, unsigned int *p_num_sg,
goto out;
}
- iov[num_sg].iov_base = cpu_physical_memory_map(pa, &len, is_write);
+ iov[num_sg].iov_base = dma_memory_map(vdev->dma_as, pa, &len,
+ is_write ?
+ DMA_DIRECTION_FROM_DEVICE :
+ DMA_DIRECTION_TO_DEVICE);
if (!iov[num_sg].iov_base) {
virtio_error(vdev, "virtio: bogus descriptor or out of resources");
goto out;
@@ -597,9 +603,9 @@ static void virtqueue_undo_map_desc(unsigned int out_num, unsigned int in_num,
}
}
-static void virtqueue_map_iovec(struct iovec *sg, hwaddr *addr,
- unsigned int *num_sg, unsigned int max_size,
- int is_write)
+static void virtqueue_map_iovec(VirtIODevice *vdev, struct iovec *sg,
+ hwaddr *addr, unsigned int *num_sg,
+ unsigned int max_size, int is_write)
{
unsigned int i;
hwaddr len;
@@ -618,7 +624,10 @@ static void virtqueue_map_iovec(struct iovec *sg, hwaddr *addr,
for (i = 0; i < *num_sg; i++) {
len = sg[i].iov_len;
- sg[i].iov_base = cpu_physical_memory_map(addr[i], &len, is_write);
+ sg[i].iov_base = dma_memory_map(vdev->dma_as,
+ addr[i], &len, is_write ?
+ DMA_DIRECTION_FROM_DEVICE :
+ DMA_DIRECTION_TO_DEVICE);
if (!sg[i].iov_base) {
error_report("virtio: error trying to map MMIO memory");
exit(1);
@@ -630,12 +639,15 @@ static void virtqueue_map_iovec(struct iovec *sg, hwaddr *addr,
}
}
-void virtqueue_map(VirtQueueElement *elem)
+void virtqueue_map(VirtIODevice *vdev, VirtQueueElement *elem)
{
- virtqueue_map_iovec(elem->in_sg, elem->in_addr, &elem->in_num,
- VIRTQUEUE_MAX_SIZE, 1);
- virtqueue_map_iovec(elem->out_sg, elem->out_addr, &elem->out_num,
- VIRTQUEUE_MAX_SIZE, 0);
+ virtqueue_map_iovec(vdev, elem->in_sg, elem->in_addr, &elem->in_num,
+ MIN(ARRAY_SIZE(elem->in_sg), ARRAY_SIZE(elem->in_addr)),
+ 1);
+ virtqueue_map_iovec(vdev, elem->out_sg, elem->out_addr, &elem->out_num,
+ MIN(ARRAY_SIZE(elem->out_sg),
+ ARRAY_SIZE(elem->out_addr)),
+ 0);
}
static void *virtqueue_alloc_element(size_t sz, unsigned out_num, unsigned in_num)
@@ -771,6 +783,44 @@ err_undo_map:
return NULL;
}
+/* virtqueue_drop_all:
+ * @vq: The #VirtQueue
+ * Drops all queued buffers and indicates them to the guest
+ * as if they are done. Useful when buffers can not be
+ * processed but must be returned to the guest.
+ */
+unsigned int virtqueue_drop_all(VirtQueue *vq)
+{
+ unsigned int dropped = 0;
+ VirtQueueElement elem = {};
+ VirtIODevice *vdev = vq->vdev;
+ bool fEventIdx = virtio_vdev_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX);
+
+ if (unlikely(vdev->broken)) {
+ return 0;
+ }
+
+ while (!virtio_queue_empty(vq) && vq->inuse < vq->vring.num) {
+ /* works similar to virtqueue_pop but does not map buffers
+ * and does not allocate any memory */
+ smp_rmb();
+ if (!virtqueue_get_head(vq, vq->last_avail_idx, &elem.index)) {
+ break;
+ }
+ vq->inuse++;
+ vq->last_avail_idx++;
+ if (fEventIdx) {
+ vring_set_avail_event(vq, vq->last_avail_idx);
+ }
+ /* immediately push the element, nothing to unmap
+ * as both in_num and out_num are set to 0 */
+ virtqueue_push(vq, &elem, 0);
+ dropped++;
+ }
+
+ return dropped;
+}
+
/* Reading and writing a structure directly to QEMUFile is *awful*, but
* it is what QEMU has always done by mistake. We can change it sooner
* or later by bumping the version number of the affected vm states.
@@ -788,7 +838,7 @@ typedef struct VirtQueueElementOld {
struct iovec out_sg[VIRTQUEUE_MAX_SIZE];
} VirtQueueElementOld;
-void *qemu_get_virtqueue_element(QEMUFile *f, size_t sz)
+void *qemu_get_virtqueue_element(VirtIODevice *vdev, QEMUFile *f, size_t sz)
{
VirtQueueElement *elem;
VirtQueueElementOld data;
@@ -819,7 +869,7 @@ void *qemu_get_virtqueue_element(QEMUFile *f, size_t sz)
elem->out_sg[i].iov_len = data.out_sg[i].iov_len;
}
- virtqueue_map(elem);
+ virtqueue_map(vdev, elem);
return elem;
}
@@ -878,6 +928,11 @@ static int virtio_validate_features(VirtIODevice *vdev)
{
VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev);
+ if (virtio_host_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM) &&
+ !virtio_vdev_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM)) {
+ return -EFAULT;
+ }
+
if (k->validate_features) {
return k->validate_features(vdev);
} else {
@@ -1861,9 +1916,11 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id)
/*
* Some devices migrate VirtQueueElements that have been popped
* from the avail ring but not yet returned to the used ring.
+ * Since max ring size < UINT16_MAX it's safe to use modulo
+ * UINT16_MAX + 1 subtraction.
*/
- vdev->vq[i].inuse = vdev->vq[i].last_avail_idx -
- vdev->vq[i].used_idx;
+ vdev->vq[i].inuse = (uint16_t)(vdev->vq[i].last_avail_idx -
+ vdev->vq[i].used_idx);
if (vdev->vq[i].inuse > vdev->vq[i].vring.num) {
error_report("VQ %d size 0x%x < last_avail_idx 0x%x - "
"used_idx 0x%x",
@@ -2001,6 +2058,11 @@ void virtio_queue_set_last_avail_idx(VirtIODevice *vdev, int n, uint16_t idx)
vdev->vq[n].shadow_avail_idx = idx;
}
+void virtio_queue_update_used_idx(VirtIODevice *vdev, int n)
+{
+ vdev->vq[n].used_idx = vring_used_idx(&vdev->vq[n]);
+}
+
void virtio_queue_invalidate_signalled_used(VirtIODevice *vdev, int n)
{
vdev->vq[n].signalled_used_valid = false;