mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-15 22:21:57 -06:00
vhost: set vring endianness for legacy virtio
Legacy virtio is native endian: if the guest and host endianness differ, we have to tell vhost so it can swap bytes where appropriate. This is done through a vhost ring ioctl. Signed-off-by: Greg Kurz <gkurz@linux.vnet.ibm.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
parent
41d283bdab
commit
04b7a1523d
1 changed files with 49 additions and 1 deletions
|
@ -17,9 +17,11 @@
|
||||||
#include "hw/hw.h"
|
#include "hw/hw.h"
|
||||||
#include "qemu/atomic.h"
|
#include "qemu/atomic.h"
|
||||||
#include "qemu/range.h"
|
#include "qemu/range.h"
|
||||||
|
#include "qemu/error-report.h"
|
||||||
#include <linux/vhost.h>
|
#include <linux/vhost.h>
|
||||||
#include "exec/address-spaces.h"
|
#include "exec/address-spaces.h"
|
||||||
#include "hw/virtio/virtio-bus.h"
|
#include "hw/virtio/virtio-bus.h"
|
||||||
|
#include "hw/virtio/virtio-access.h"
|
||||||
#include "migration/migration.h"
|
#include "migration/migration.h"
|
||||||
|
|
||||||
static struct vhost_log *vhost_log;
|
static struct vhost_log *vhost_log;
|
||||||
|
@ -686,6 +688,27 @@ static void vhost_log_stop(MemoryListener *listener,
|
||||||
/* FIXME: implement */
|
/* FIXME: implement */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int vhost_virtqueue_set_vring_endian_legacy(struct vhost_dev *dev,
|
||||||
|
bool is_big_endian,
|
||||||
|
int vhost_vq_index)
|
||||||
|
{
|
||||||
|
struct vhost_vring_state s = {
|
||||||
|
.index = vhost_vq_index,
|
||||||
|
.num = is_big_endian
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!dev->vhost_ops->vhost_call(dev, VHOST_SET_VRING_ENDIAN, &s)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errno == ENOTTY) {
|
||||||
|
error_report("vhost does not support cross-endian");
|
||||||
|
return -ENOSYS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
|
||||||
static int vhost_virtqueue_start(struct vhost_dev *dev,
|
static int vhost_virtqueue_start(struct vhost_dev *dev,
|
||||||
struct VirtIODevice *vdev,
|
struct VirtIODevice *vdev,
|
||||||
struct vhost_virtqueue *vq,
|
struct vhost_virtqueue *vq,
|
||||||
|
@ -716,6 +739,16 @@ static int vhost_virtqueue_start(struct vhost_dev *dev,
|
||||||
return -errno;
|
return -errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1) &&
|
||||||
|
virtio_legacy_is_cross_endian(vdev)) {
|
||||||
|
r = vhost_virtqueue_set_vring_endian_legacy(dev,
|
||||||
|
virtio_is_big_endian(vdev),
|
||||||
|
vhost_vq_index);
|
||||||
|
if (r) {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
s = l = virtio_queue_get_desc_size(vdev, idx);
|
s = l = virtio_queue_get_desc_size(vdev, idx);
|
||||||
a = virtio_queue_get_desc_addr(vdev, idx);
|
a = virtio_queue_get_desc_addr(vdev, idx);
|
||||||
vq->desc = cpu_physical_memory_map(a, &l, 0);
|
vq->desc = cpu_physical_memory_map(a, &l, 0);
|
||||||
|
@ -786,8 +819,9 @@ static void vhost_virtqueue_stop(struct vhost_dev *dev,
|
||||||
struct vhost_virtqueue *vq,
|
struct vhost_virtqueue *vq,
|
||||||
unsigned idx)
|
unsigned idx)
|
||||||
{
|
{
|
||||||
|
int vhost_vq_index = idx - dev->vq_index;
|
||||||
struct vhost_vring_state state = {
|
struct vhost_vring_state state = {
|
||||||
.index = idx - dev->vq_index
|
.index = vhost_vq_index,
|
||||||
};
|
};
|
||||||
int r;
|
int r;
|
||||||
assert(idx >= dev->vq_index && idx < dev->vq_index + dev->nvqs);
|
assert(idx >= dev->vq_index && idx < dev->vq_index + dev->nvqs);
|
||||||
|
@ -798,6 +832,20 @@ static void vhost_virtqueue_stop(struct vhost_dev *dev,
|
||||||
}
|
}
|
||||||
virtio_queue_set_last_avail_idx(vdev, idx, state.num);
|
virtio_queue_set_last_avail_idx(vdev, idx, state.num);
|
||||||
virtio_queue_invalidate_signalled_used(vdev, idx);
|
virtio_queue_invalidate_signalled_used(vdev, idx);
|
||||||
|
|
||||||
|
/* In the cross-endian case, we need to reset the vring endianness to
|
||||||
|
* native as legacy devices expect so by default.
|
||||||
|
*/
|
||||||
|
if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1) &&
|
||||||
|
virtio_legacy_is_cross_endian(vdev)) {
|
||||||
|
r = vhost_virtqueue_set_vring_endian_legacy(dev,
|
||||||
|
!virtio_is_big_endian(vdev),
|
||||||
|
vhost_vq_index);
|
||||||
|
if (r < 0) {
|
||||||
|
error_report("failed to reset vring endianness");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
assert (r >= 0);
|
assert (r >= 0);
|
||||||
cpu_physical_memory_unmap(vq->ring, virtio_queue_get_ring_size(vdev, idx),
|
cpu_physical_memory_unmap(vq->ring, virtio_queue_get_ring_size(vdev, idx),
|
||||||
0, virtio_queue_get_ring_size(vdev, idx));
|
0, virtio_queue_get_ring_size(vdev, idx));
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue