This patch implements the core of save/restore support for virtio. It's modelled after how PCI save/restore works.
N.B. This makes savevm/loadvm work, but not live migration. The issue with live migration is that we're manipulating guest memory without updating the dirty bitmap correctly. I will submit a patch in the near future that addresses that problem. Signed-off-by: Anthony Liguori <aliguori> diff --git a/qemu/hw/virtio.c b/qemu/hw/virtio.c index a4c9d10..440cc69 100644 --- a/qemu/hw/virtio.c +++ b/qemu/hw/virtio.c @@ -420,7 +420,6 @@ VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size, vdev->vq[i].vring.num = queue_size; vdev->vq[i].handle_output = handle_output; - vdev->vq[i].index = i; return &vdev->vq[i]; } @@ -436,6 +435,71 @@ void virtio_notify(VirtIODevice *vdev, VirtQueue *vq) virtio_update_irq(vdev); } +void virtio_save(VirtIODevice *vdev, QEMUFile *f) +{ + int i; + + pci_device_save(&vdev->pci_dev, f); + + qemu_put_be32s(f, &vdev->addr); + qemu_put_8s(f, &vdev->status); + qemu_put_8s(f, &vdev->isr); + qemu_put_be16s(f, &vdev->queue_sel); + qemu_put_be32s(f, &vdev->features); + qemu_put_be32(f, vdev->config_len); + qemu_put_buffer(f, vdev->config, vdev->config_len); + + for (i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) { + if (vdev->vq[i].vring.num == 0) + break; + } + + qemu_put_be32(f, i); + + for (i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) { + if (vdev->vq[i].vring.num == 0) + break; + + qemu_put_be32(f, vdev->vq[i].vring.num); + qemu_put_be32s(f, &vdev->vq[i].pfn); + qemu_put_be16s(f, &vdev->vq[i].last_avail_idx); + } +} + +void virtio_load(VirtIODevice *vdev, QEMUFile *f) +{ + int num, i; + + pci_device_load(&vdev->pci_dev, f); + + qemu_get_be32s(f, &vdev->addr); + qemu_get_8s(f, &vdev->status); + qemu_get_8s(f, &vdev->isr); + qemu_get_be16s(f, &vdev->queue_sel); + qemu_get_be32s(f, &vdev->features); + vdev->config_len = qemu_get_be32(f); + qemu_get_buffer(f, vdev->config, vdev->config_len); + + num = qemu_get_be32(f); + + for (i = 0; i < num; i++) { + vdev->vq[i].vring.num = qemu_get_be32(f); + qemu_get_be32s(f, &vdev->vq[i].pfn); + qemu_get_be16s(f, &vdev->vq[i].last_avail_idx); + + if (vdev->vq[i].pfn) { + size_t size; + target_phys_addr_t pa; + + pa = (ram_addr_t)vdev->vq[i].pfn << TARGET_PAGE_BITS; + size = virtqueue_size(vdev->vq[i].vring.num); + virtqueue_init(&vdev->vq[i], virtio_map_gpa(pa, size)); + } + } + + virtio_update_irq(vdev); +} + VirtIODevice *virtio_init_pci(PCIBus *bus, const char *name, uint16_t vendor, uint16_t device, uint16_t subvendor, uint16_t subdevice, diff --git a/qemu/hw/virtio.h b/qemu/hw/virtio.h index dee97ba..ed8cfd6 100644 --- a/qemu/hw/virtio.h +++ b/qemu/hw/virtio.h @@ -87,7 +87,6 @@ struct VirtQueue uint32_t pfn; uint16_t last_avail_idx; void (*handle_output)(VirtIODevice *vdev, VirtQueue *vq); - int index; }; #define VIRTQUEUE_MAX_SIZE 1024 @@ -108,8 +107,6 @@ struct VirtIODevice PCIDevice pci_dev; const char *name; uint32_t addr; - uint16_t vendor; - uint16_t device; uint8_t status; uint8_t isr; uint16_t queue_sel; @@ -140,4 +137,8 @@ int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem); void virtio_notify(VirtIODevice *vdev, VirtQueue *vq); +void virtio_save(VirtIODevice *vdev, QEMUFile *f); + +void virtio_load(VirtIODevice *vdev, QEMUFile *f); + #endif ------------------------------------------------------------------------- This SF.net email is sponsored by the 2008 JavaOne(SM) Conference Don't miss this year's exciting event. There's still time to save $100. Use priority code J8TL2D2. http://ad.doubleclick.net/clk;198757673;13503038;p?http://java.sun.com/javaone _______________________________________________ kvm-devel mailing list kvm-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/kvm-devel