Signed-off-by: Paolo Bonzini <[email protected]>
---
hw/virtio/virtio.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 93 insertions(+), 2 deletions(-)
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index fd63206..f5f8108 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -578,14 +578,105 @@ void *virtqueue_pop(VirtQueue *vq, size_t sz)
void *qemu_get_virtqueue_element(QEMUFile *f, size_t sz)
{
VirtQueueElement *elem = g_malloc(sz);
- qemu_get_buffer(f, (uint8_t *)elem, sizeof(VirtQueueElement));
+ bool swap;
+ hwaddr addr[VIRTQUEUE_MAX_SIZE];
+ struct iovec iov[VIRTQUEUE_MAX_SIZE];
+ uint64_t scratch;
+ int i;
+
+ qemu_get_be32s(f, &elem->index);
+ qemu_get_be32s(f, &elem->out_num);
+ qemu_get_be32s(f, &elem->in_num);
+
+ swap = (elem->out_num & 0xFFFF0000) || (elem->in_num & 0xFFFF0000);
+ if (swap) {
+ bswap32s(&elem->index);
+ bswap32s(&elem->out_num);
+ bswap32s(&elem->in_num);
+ }
+
+ for (i = 0; i < elem->in_num; i++) {
+ qemu_get_be64s(f, &elem->in_addr[i]);
+ if (swap) {
+ bswap64s(&elem->in_addr[i]);
+ }
+ }
+ if (i < ARRAY_SIZE(addr)) {
+ qemu_get_buffer(f, (uint8_t *)addr, sizeof(addr) - i *
sizeof(addr[0]));
+ }
+
+ for (i = 0; i < elem->out_num; i++) {
+ qemu_get_be64s(f, &elem->out_addr[i]);
+ if (swap) {
+ bswap64s(&elem->out_addr[i]);
+ }
+ }
+ if (i < ARRAY_SIZE(addr)) {
+ qemu_get_buffer(f, (uint8_t *)addr, sizeof(addr) - i *
sizeof(addr[0]));
+ }
+
+ for (i = 0; i < elem->in_num; i++) {
+ (void) qemu_get_be64(f); /* base */
+ qemu_get_be64s(f, &scratch); /* length */
+ if (swap) {
+ bswap64s(&scratch);
+ }
+ elem->in_sg[i].iov_len = scratch;
+ }
+ if (i < ARRAY_SIZE(iov)) {
+ qemu_get_buffer(f, (uint8_t *)iov, sizeof(iov) - i * sizeof(iov[0]));
+ }
+
+ for (i = 0; i < elem->out_num; i++) {
+ (void) qemu_get_be64(f); /* base */
+ qemu_get_be64s(f, &scratch); /* length */
+ if (swap) {
+ bswap64s(&scratch);
+ }
+ elem->out_sg[i].iov_len = scratch;
+ }
+ if (i < ARRAY_SIZE(iov)) {
+ qemu_get_buffer(f, (uint8_t *)iov, sizeof(iov) - i * sizeof(iov[0]));
+ }
+
virtqueue_map(elem);
return elem;
}
void qemu_put_virtqueue_element(QEMUFile *f, VirtQueueElement *elem)
{
- qemu_put_buffer(f, (uint8_t *)elem, sizeof(VirtQueueElement));
+ hwaddr addr[VIRTQUEUE_MAX_SIZE];
+ struct iovec iov[VIRTQUEUE_MAX_SIZE];
+ int i;
+
+ memset(addr, 0, sizeof(addr));
+ memset(iov, 0, sizeof(iov));
+
+ qemu_put_be32s(f, &elem->index);
+ qemu_put_be32s(f, &elem->out_num);
+ qemu_put_be32s(f, &elem->in_num);
+
+ for (i = 0; i < elem->in_num; i++) {
+ qemu_put_be64s(f, &elem->in_addr[i]);
+ }
+ qemu_put_buffer(f, (uint8_t *)addr, sizeof(addr) - i * sizeof(addr[0]));
+
+ for (i = 0; i < elem->out_num; i++) {
+ qemu_put_be64s(f, &elem->out_addr[i]);
+ }
+ qemu_put_buffer(f, (uint8_t *)addr, sizeof(addr) - i * sizeof(addr[0]));
+
+ for (i = 0; i < elem->in_num; i++) {
+ qemu_put_be64(f, 0);
+ qemu_put_be64(f, elem->in_sg[i].iov_len);
+ }
+ qemu_put_buffer(f, (uint8_t *)iov, sizeof(iov) - i * sizeof(iov[0]));
+
+ for (i = 0; i < elem->out_num; i++) {
+ qemu_put_be64(f, 0);
+ qemu_put_be64(f, elem->out_sg[i].iov_len);
+ }
+ qemu_put_buffer(f, (uint8_t *)iov, sizeof(iov) - i * sizeof(iov[0]));
}
/* virtio device */
--
1.8.3.1