Blob Blame History Raw
From e55e5fd43113a5b266efa6d17e44f0e9231a98ed Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Wed, 25 Aug 2010 16:08:37 +0000
Subject: [PATCH 31/39] qxl: savevm fixes

---
 hw/qxl.c |  125 +++++++++++++++++++++++++++++++++++++++++++++----------------
 hw/qxl.h |    6 +++
 2 files changed, 98 insertions(+), 33 deletions(-)

diff --git a/hw/qxl.c b/hw/qxl.c
index 86c0e03..4a15200 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -1087,6 +1087,14 @@ static void qxl_vm_change_state_handler(void *opaque, int running, int reason)
 {
     PCIQXLDevice *qxl = opaque;
     qemu_spice_vm_change_state_handler(&qxl->ssd, running, reason);
+
+    if (!running && qxl->mode == QXL_MODE_NATIVE) {
+        /* dirty all vram (which holds surfaces) to make sure it is saved */
+        /* FIXME #1: should go out during "live" stage */
+        /* FIXME #2: we only need to save the areas which are actually used */
+        ram_addr_t addr = qxl->vram_offset;
+        qxl_set_dirty(addr, addr + qxl->vram_size);
+    }
 }

 /* display change listener */
@@ -1134,6 +1142,8 @@ static int qxl_init(PCIDevice *dev)
     qxl->id = device_id;
     qxl->mode = QXL_MODE_UNDEFINED;
     qxl->generation = 1;
+    qxl->num_memslots = NUM_MEMSLOTS;
+    qxl->num_surfaces = NUM_SURFACES;

     switch (qxl->revision) {
     case 1: /* spice 0.4 -- qxl-1 */
@@ -1183,7 +1193,8 @@ static int qxl_init(PCIDevice *dev)
         if (ram_size < 16 * 1024 * 1024)
             ram_size = 16 * 1024 * 1024;
         qxl->vga.vram_size = ram_size;
-        qxl->vga.vram_offset = qemu_ram_alloc(&qxl->pci.qdev, "bar0", qxl->vga.vram_size);
+        qxl->vga.vram_offset = qemu_ram_alloc(&qxl->pci.qdev, "qxl.vgavram",
+                                              qxl->vga.vram_size);
         qxl->vga.vram_ptr = qemu_get_ram_ptr(qxl->vga.vram_offset);

         pci_config_set_class(config, PCI_CLASS_DISPLAY_OTHER);
@@ -1195,14 +1206,14 @@ static int qxl_init(PCIDevice *dev)
     pci_set_byte(&config[PCI_INTERRUPT_PIN], 1);

     qxl->rom_size = qxl_rom_size();
-    qxl->rom_offset = qemu_ram_alloc(&qxl->pci.qdev, "bar2", qxl->rom_size);
+    qxl->rom_offset = qemu_ram_alloc(&qxl->pci.qdev, "qxl.vrom", qxl->rom_size);
     init_qxl_rom(qxl);
     init_qxl_ram(qxl);

     if (qxl->vram_size < 16 * 1024 * 1024)
         qxl->vram_size = 16 * 1024 * 1024;
     qxl->vram_size = msb_mask(qxl->vram_size * 2 - 1);
-    qxl->vram_offset = qemu_ram_alloc(&qxl->pci.qdev, "bar1", qxl->vram_size);
+    qxl->vram_offset = qemu_ram_alloc(&qxl->pci.qdev, "qxl.vram", qxl->vram_size);

     pci_register_bar(&qxl->pci, QXL_IO_RANGE_INDEX,
                      msb_mask(QXL_IO_RANGE_SIZE * 2 - 1),
@@ -1237,14 +1248,12 @@ static void qxl_pre_save(void *opaque)
     uint8_t *ram_start = d->vga.vram_ptr;

     dprintf(d, 1, "%s:\n", __FUNCTION__);
-#if 1 /* wanna zap this */
     if (d->last_release == NULL) {
         d->last_release_offset = 0;
     } else {
         d->last_release_offset = (uint8_t *)d->last_release - ram_start;
     }
     assert(d->last_release_offset < d->vga.vram_size);
-#endif
 }

 static int qxl_pre_load(void *opaque)
@@ -1306,29 +1315,55 @@ static int qxl_post_load(void *opaque, int version)
     }
     dprintf(d, 1, "%s: done\n", __FUNCTION__);

-#if 1 /* wanna zap this */
-    if (d->last_release_offset >= d->vga.vram_size) {
-        dprintf(d, 1, "%s: invalid last_release_offset %u, ram_size %u\n",
-                __FUNCTION__, d->last_release_offset, d->vga.vram_size);
-        exit(-1);
-    }
-
+    assert(d->last_release_offset < d->vga.vram_size);
     if (d->last_release_offset == 0) {
         d->last_release = NULL;
     } else {
         d->last_release = (QXLReleaseInfo *)(ram_start + d->last_release_offset);
     }
-#endif
+
+    /* spice 0.4 compatibility -- accept but ignore */
+    free(d->worker_data);
+    d->worker_data = NULL;
+    d->worker_data_size = 0;

     return 0;
 }

-#define QXL_VER 1
+#define QXL_SAVE_VERSION 20
+
+static bool qxl_test_worker_data(void *opaque, int version_id)
+{
+    PCIQXLDevice* d = opaque;
+
+    if (d->revision != 1) {
+        return false;
+    }
+    if (!d->worker_data_size) {
+        return false;
+    }
+    if (!d->worker_data) {
+        d->worker_data = qemu_malloc(d->worker_data_size);
+    }
+    return true;
+}
+
+static bool qxl_test_spice04(void *opaque, int version_id)
+{
+    PCIQXLDevice* d = opaque;
+    return d->revision == 1;
+}
+
+static bool qxl_test_spice06(void *opaque)
+{
+    PCIQXLDevice* d = opaque;
+    return d->revision > 1;
+}

 static VMStateDescription qxl_memslot = {
     .name               = "qxl-memslot",
-    .version_id         = QXL_VER,
-    .minimum_version_id = QXL_VER,
+    .version_id         = QXL_SAVE_VERSION,
+    .minimum_version_id = QXL_SAVE_VERSION,
     .fields = (VMStateField[]) {
         VMSTATE_UINT64(slot.mem_start, struct guest_slots),
         VMSTATE_UINT64(slot.mem_end,   struct guest_slots),
@@ -1339,8 +1374,8 @@ static VMStateDescription qxl_memslot = {

 static VMStateDescription qxl_surface = {
     .name               = "qxl-surface",
-    .version_id         = QXL_VER,
-    .minimum_version_id = QXL_VER,
+    .version_id         = QXL_SAVE_VERSION,
+    .minimum_version_id = QXL_SAVE_VERSION,
     .fields = (VMStateField[]) {
         VMSTATE_UINT32(width,      QXLSurfaceCreate),
         VMSTATE_UINT32(height,     QXLSurfaceCreate),
@@ -1355,34 +1390,58 @@ static VMStateDescription qxl_surface = {
     }
 };

+static VMStateDescription qxl_vmstate_spice06 = {
+    .name               = "qxl/spice06",
+    .version_id         = QXL_SAVE_VERSION,
+    .minimum_version_id = QXL_SAVE_VERSION,
+    .fields = (VMStateField []) {
+        VMSTATE_INT32_EQUAL(num_memslots, PCIQXLDevice),
+        VMSTATE_STRUCT_ARRAY(guest_slots, PCIQXLDevice, NUM_MEMSLOTS, 0,
+                             qxl_memslot, struct guest_slots),
+        VMSTATE_STRUCT(guest_primary.surface, PCIQXLDevice, 0,
+                       qxl_surface, QXLSurfaceCreate),
+        VMSTATE_INT32_EQUAL(num_surfaces, PCIQXLDevice),
+        VMSTATE_ARRAY(guest_surfaces.cmds, PCIQXLDevice, NUM_SURFACES, 0,
+                      vmstate_info_uint64, uint64_t),
+        VMSTATE_UINT64(guest_cursor, PCIQXLDevice),
+        VMSTATE_END_OF_LIST()
+    },
+};
+
 static VMStateDescription qxl_vmstate = {
     .name               = "qxl",
-    .version_id         = QXL_VER,
-    .minimum_version_id = QXL_VER,
+    .version_id         = QXL_SAVE_VERSION,
+    .minimum_version_id = QXL_SAVE_VERSION,
     .pre_save           = qxl_pre_save,
     .pre_load           = qxl_pre_load,
     .post_load          = qxl_post_load,
     .fields = (VMStateField []) {
         VMSTATE_PCI_DEVICE(pci, PCIQXLDevice),
-        VMSTATE_STRUCT(vga, PCIQXLDevice, QXL_VER, vmstate_vga_common, VGACommonState),
+        VMSTATE_STRUCT(vga, PCIQXLDevice, 0, vmstate_vga_common, VGACommonState),
         VMSTATE_UINT32(shadow_rom.mode, PCIQXLDevice),
-#if 1 /* wanna zap this */
         VMSTATE_UINT32(num_free_res, PCIQXLDevice),
         VMSTATE_UINT32(last_release_offset, PCIQXLDevice),
-#endif
         VMSTATE_UINT32(mode, PCIQXLDevice),
         VMSTATE_UINT32(ssd.unique, PCIQXLDevice),
-#if 1 /* new stuff */
-        VMSTATE_STRUCT_ARRAY(guest_slots, PCIQXLDevice, NUM_MEMSLOTS, QXL_VER,
-                             qxl_memslot, struct guest_slots),
-        VMSTATE_STRUCT(guest_primary.surface, PCIQXLDevice, QXL_VER,
-                       qxl_surface, QXLSurfaceCreate),
-        VMSTATE_ARRAY(guest_surfaces.cmds, PCIQXLDevice, NUM_SURFACES, QXL_VER,
-                      vmstate_info_uint64, uint64_t),
-        VMSTATE_UINT64(guest_cursor, PCIQXLDevice),
-#endif
+
+        /* spice 0.4 sends/expects them */
+        VMSTATE_VBUFFER_UINT32(vga.vram_ptr, PCIQXLDevice, 0, qxl_test_spice04, 0,
+                               vga.vram_size),
+        VMSTATE_UINT32_TEST(worker_data_size, PCIQXLDevice, qxl_test_spice04),
+        VMSTATE_VBUFFER_UINT32(worker_data, PCIQXLDevice, 0, qxl_test_worker_data, 0,
+                               worker_data_size),
+
         VMSTATE_END_OF_LIST()
-    }
+    },
+    .subsections = (VMStateSubsection[]) {
+        {
+            /* additional spice 0.6 state */
+            .vmsd   = &qxl_vmstate_spice06,
+            .needed = qxl_test_spice06,
+        },{
+            /* end of list */
+        },
+    },
 };

 static PCIDeviceInfo qxl_info = {
diff --git a/hw/qxl.h b/hw/qxl.h
index 1216405..caf3684 100644
--- a/hw/qxl.h
+++ b/hw/qxl.h
@@ -24,6 +24,9 @@ typedef struct PCIQXLDevice {
     int                generation;
     uint32_t           revision;

+    int32_t            num_memslots;
+    int32_t            num_surfaces;
+
     struct guest_slots {
         QXLMemSlot     slot;
         void           *ptr;
@@ -74,6 +77,9 @@ typedef struct PCIQXLDevice {
     /* io bar */
     uint32_t           io_base;

+    /* spice 0.4 loadvm compatibility */
+    void               *worker_data;
+    uint32_t           worker_data_size;
 } PCIQXLDevice;

 #define PANIC_ON(x) if ((x)) {                         \
-- 
1.7.2.3