Blame 0014-spice-add-qxl-device.patch

Justin M. Forbes a81953
From 4cd79eae3a476fda86b67a8075735a03c1254a08 Mon Sep 17 00:00:00 2001
Justin M. Forbes a81953
From: Gerd Hoffmann <kraxel@redhat.com>
Justin M. Forbes a81953
Date: Tue, 27 Apr 2010 11:50:11 +0200
Justin M. Forbes a81953
Subject: [PATCH 14/39] spice: add qxl device
Justin M. Forbes a81953
Justin M. Forbes a81953
qxl is a paravirtual graphics card.  The qxl device is the bridge
Justin M. Forbes a81953
between the guest and the spice server (aka libspice-server).  The
Justin M. Forbes a81953
spice server will send the rendering commands to the spice client, which
Justin M. Forbes a81953
will actually render them.
Justin M. Forbes a81953
Justin M. Forbes a81953
The spice server is also able to render locally, which is done in case
Justin M. Forbes a81953
the guest wants read something from video memory.  Local rendering is
Justin M. Forbes a81953
also used to support display over vnc and sdl.
Justin M. Forbes a81953
Justin M. Forbes a81953
qxl is activated using "-vga qxl".  qxl supports multihead, additional
Justin M. Forbes a81953
cards can be added via '-device qxl".
Justin M. Forbes a81953
---
Justin M. Forbes a81953
 Makefile.target |    1 +
Justin M. Forbes a81953
 hw/hw.h         |   14 +
Justin M. Forbes a81953
 hw/pc.c         |    8 +
Justin M. Forbes a81953
 hw/qxl-logger.c |  179 +++++++
Justin M. Forbes a81953
 hw/qxl-render.c |  207 ++++++++
Justin M. Forbes a81953
 hw/qxl.c        | 1411 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
Justin M. Forbes a81953
 hw/qxl.h        |  102 ++++
Justin M. Forbes a81953
 hw/vga_int.h    |    2 +-
Justin M. Forbes a81953
 sysemu.h        |    3 +-
Justin M. Forbes a81953
 vl.c            |    4 +-
Justin M. Forbes a81953
 10 files changed, 1928 insertions(+), 3 deletions(-)
Justin M. Forbes a81953
 create mode 100644 hw/qxl-logger.c
Justin M. Forbes a81953
 create mode 100644 hw/qxl-render.c
Justin M. Forbes a81953
 create mode 100644 hw/qxl.c
Justin M. Forbes a81953
 create mode 100644 hw/qxl.h
Justin M. Forbes a81953
Justin M. Forbes a81953
diff --git a/Makefile.target b/Makefile.target
Justin M. Forbes a81953
index 9e13d99..4da33b5 100644
Justin M. Forbes a81953
--- a/Makefile.target
Justin M. Forbes a81953
+++ b/Makefile.target
Justin M. Forbes a81953
@@ -216,6 +216,7 @@ obj-i386-y += debugcon.o multiboot.o
Justin M. Forbes a81953
 obj-i386-y += pc_piix.o
Justin M. Forbes a81953
 obj-i386-y += testdev.o
Justin M. Forbes a81953
 obj-i386-y += acpi.o acpi_piix4.o
Justin M. Forbes a81953
+obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o
Justin M. Forbes a81953
Justin M. Forbes a81953
 obj-i386-y += pcspk.o i8254.o
Justin M. Forbes a81953
 obj-i386-$(CONFIG_KVM_PIT) += i8254-kvm.o
Justin M. Forbes a81953
diff --git a/hw/hw.h b/hw/hw.h
Justin M. Forbes a81953
index ec6985d..044ebfb 100644
Justin M. Forbes a81953
--- a/hw/hw.h
Justin M. Forbes a81953
+++ b/hw/hw.h
Justin M. Forbes a81953
@@ -528,6 +528,17 @@ extern const VMStateInfo vmstate_info_unused_buffer;
Justin M. Forbes a81953
     .start        = (_start),                                        \
Justin M. Forbes a81953
 }
Justin M. Forbes a81953
Justin M. Forbes a81953
+#define VMSTATE_VBUFFER_UINT32(_field, _state, _version, _test, _start, _field_size) { \
Justin M. Forbes a81953
+    .name         = (stringify(_field)),                             \
Justin M. Forbes a81953
+    .version_id   = (_version),                                      \
Justin M. Forbes a81953
+    .field_exists = (_test),                                         \
Justin M. Forbes a81953
+    .size_offset  = vmstate_offset_value(_state, _field_size, uint32_t),\
Justin M. Forbes a81953
+    .info         = &vmstate_info_buffer,                            \
Justin M. Forbes a81953
+    .flags        = VMS_VBUFFER|VMS_POINTER,                         \
Justin M. Forbes a81953
+    .offset       = offsetof(_state, _field),                        \
Justin M. Forbes a81953
+    .start        = (_start),                                        \
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
 #define VMSTATE_BUFFER_UNSAFE_INFO(_field, _state, _version, _info, _size) { \
Justin M. Forbes a81953
     .name       = (stringify(_field)),                               \
Justin M. Forbes a81953
     .version_id = (_version),                                        \
Justin M. Forbes a81953
@@ -742,6 +753,9 @@ extern const VMStateDescription vmstate_i2c_slave;
Justin M. Forbes a81953
 #define VMSTATE_PARTIAL_VBUFFER(_f, _s, _size)                        \
Justin M. Forbes a81953
     VMSTATE_VBUFFER(_f, _s, 0, NULL, 0, _size)
Justin M. Forbes a81953
Justin M. Forbes a81953
+#define VMSTATE_PARTIAL_VBUFFER_UINT32(_f, _s, _size)                        \
Justin M. Forbes a81953
+    VMSTATE_VBUFFER_UINT32(_f, _s, 0, NULL, 0, _size)
Justin M. Forbes a81953
+
Justin M. Forbes a81953
 #define VMSTATE_SUB_VBUFFER(_f, _s, _start, _size)                    \
Justin M. Forbes a81953
     VMSTATE_VBUFFER(_f, _s, 0, NULL, _start, _size)
Justin M. Forbes a81953
Justin M. Forbes a81953
diff --git a/hw/pc.c b/hw/pc.c
Justin M. Forbes a81953
index 77b1592..1f2df2f 100644
Justin M. Forbes a81953
--- a/hw/pc.c
Justin M. Forbes a81953
+++ b/hw/pc.c
Justin M. Forbes a81953
@@ -41,6 +41,7 @@
Justin M. Forbes a81953
 #include "sysemu.h"
Justin M. Forbes a81953
 #include "device-assignment.h"
Justin M. Forbes a81953
 #include "kvm.h"
Justin M. Forbes a81953
+#include "qemu-spice.h"
Justin M. Forbes a81953
Justin M. Forbes a81953
 /* output Bochs bios info messages */
Justin M. Forbes a81953
 //#define DEBUG_BIOS
Justin M. Forbes a81953
@@ -1002,6 +1003,13 @@ void pc_vga_init(PCIBus *pci_bus)
Justin M. Forbes a81953
             pci_vmsvga_init(pci_bus);
Justin M. Forbes a81953
         else
Justin M. Forbes a81953
             fprintf(stderr, "%s: vmware_vga: no PCI bus\n", __FUNCTION__);
Justin M. Forbes a81953
+#ifdef CONFIG_SPICE
Justin M. Forbes a81953
+    } else if (qxl_enabled) {
Justin M. Forbes a81953
+        if (pci_bus)
Justin M. Forbes a81953
+            pci_create_simple(pci_bus, -1, "qxl");
Justin M. Forbes a81953
+        else
Justin M. Forbes a81953
+            fprintf(stderr, "%s: qxl: no PCI bus\n", __FUNCTION__);
Justin M. Forbes a81953
+#endif
Justin M. Forbes a81953
     } else if (std_vga_enabled) {
Justin M. Forbes a81953
         if (pci_bus) {
Justin M. Forbes a81953
             pci_vga_init(pci_bus, 0, 0);
Justin M. Forbes a81953
diff --git a/hw/qxl-logger.c b/hw/qxl-logger.c
Justin M. Forbes a81953
new file mode 100644
Justin M. Forbes a81953
index 0000000..d4a935a
Justin M. Forbes a81953
--- /dev/null
Justin M. Forbes a81953
+++ b/hw/qxl-logger.c
Justin M. Forbes a81953
@@ -0,0 +1,179 @@
Justin M. Forbes a81953
+/*
Justin M. Forbes a81953
+ * qxl command logging -- for debug purposes
Justin M. Forbes a81953
+ */
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+#include <stdio.h>
Justin M. Forbes a81953
+#include <stdbool.h>
Justin M. Forbes a81953
+#include <stdint.h>
Justin M. Forbes a81953
+#include <string.h>
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+#include "qxl.h"
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static const char *qxl_type[] = {
Justin M. Forbes a81953
+    [ QXL_CMD_NOP ]     = "nop",
Justin M. Forbes a81953
+    [ QXL_CMD_DRAW ]    = "draw",
Justin M. Forbes a81953
+    [ QXL_CMD_UPDATE ]  = "update",
Justin M. Forbes a81953
+    [ QXL_CMD_CURSOR ]  = "cursor",
Justin M. Forbes a81953
+    [ QXL_CMD_MESSAGE ] = "message",
Justin M. Forbes a81953
+    [ QXL_CMD_SURFACE ] = "surface",
Justin M. Forbes a81953
+};
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static const char *qxl_draw_type[] = {
Justin M. Forbes a81953
+    [ QXL_DRAW_NOP         ] = "nop",
Justin M. Forbes a81953
+    [ QXL_DRAW_FILL        ] = "fill",
Justin M. Forbes a81953
+    [ QXL_DRAW_OPAQUE      ] = "opaque",
Justin M. Forbes a81953
+    [ QXL_DRAW_COPY        ] = "copy",
Justin M. Forbes a81953
+    [ QXL_COPY_BITS        ] = "copy-bits",
Justin M. Forbes a81953
+    [ QXL_DRAW_BLEND       ] = "blend",
Justin M. Forbes a81953
+    [ QXL_DRAW_BLACKNESS   ] = "blackness",
Justin M. Forbes a81953
+    [ QXL_DRAW_WHITENESS   ] = "whitemess",
Justin M. Forbes a81953
+    [ QXL_DRAW_INVERS      ] = "invers",
Justin M. Forbes a81953
+    [ QXL_DRAW_ROP3        ] = "rop3",
Justin M. Forbes a81953
+    [ QXL_DRAW_STROKE      ] = "stroke",
Justin M. Forbes a81953
+    [ QXL_DRAW_TEXT        ] = "text",
Justin M. Forbes a81953
+    [ QXL_DRAW_TRANSPARENT ] = "transparent",
Justin M. Forbes a81953
+    [ QXL_DRAW_ALPHA_BLEND ] = "alpha-blend",
Justin M. Forbes a81953
+};
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static const char *qxl_draw_effect[] = {
Justin M. Forbes a81953
+    [ QXL_EFFECT_BLEND            ] = "blend",
Justin M. Forbes a81953
+    [ QXL_EFFECT_OPAQUE           ] = "opaque",
Justin M. Forbes a81953
+    [ QXL_EFFECT_REVERT_ON_DUP    ] = "revert-on-dup",
Justin M. Forbes a81953
+    [ QXL_EFFECT_BLACKNESS_ON_DUP ] = "blackness-on-dup",
Justin M. Forbes a81953
+    [ QXL_EFFECT_WHITENESS_ON_DUP ] = "whiteness-on-dup",
Justin M. Forbes a81953
+    [ QXL_EFFECT_NOP_ON_DUP       ] = "nop-on-dup",
Justin M. Forbes a81953
+    [ QXL_EFFECT_NOP              ] = "nop",
Justin M. Forbes a81953
+    [ QXL_EFFECT_OPAQUE_BRUSH     ] = "opaque-brush",
Justin M. Forbes a81953
+};
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static const char *qxl_surface_cmd[] = {
Justin M. Forbes a81953
+   [ QXL_SURFACE_CMD_CREATE  ] = "create",
Justin M. Forbes a81953
+   [ QXL_SURFACE_CMD_DESTROY ] = "destroy",
Justin M. Forbes a81953
+};
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static const char *spice_surface_fmt[] = {
Justin M. Forbes a81953
+   [ SPICE_SURFACE_FMT_INVALID  ] = "invalid",
Justin M. Forbes a81953
+   [ SPICE_SURFACE_FMT_1_A      ] = "alpha/1",
Justin M. Forbes a81953
+   [ SPICE_SURFACE_FMT_8_A      ] = "alpha/8",
Justin M. Forbes a81953
+   [ SPICE_SURFACE_FMT_16_555   ] = "555/16",
Justin M. Forbes a81953
+   [ SPICE_SURFACE_FMT_16_565   ] = "565/16",
Justin M. Forbes a81953
+   [ SPICE_SURFACE_FMT_32_xRGB  ] = "xRGB/32",
Justin M. Forbes a81953
+   [ SPICE_SURFACE_FMT_32_ARGB  ] = "ARGB/32",
Justin M. Forbes a81953
+};
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static const char *qxl_cursor_cmd[] = {
Justin M. Forbes a81953
+   [ QXL_CURSOR_SET   ] = "set",
Justin M. Forbes a81953
+   [ QXL_CURSOR_MOVE  ] = "move",
Justin M. Forbes a81953
+   [ QXL_CURSOR_HIDE  ] = "hide",
Justin M. Forbes a81953
+   [ QXL_CURSOR_TRAIL ] = "trail",
Justin M. Forbes a81953
+};
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static const char *spice_cursor_type[] = {
Justin M. Forbes a81953
+   [ SPICE_CURSOR_TYPE_ALPHA   ] = "alpha",
Justin M. Forbes a81953
+   [ SPICE_CURSOR_TYPE_MONO    ] = "mono",
Justin M. Forbes a81953
+   [ SPICE_CURSOR_TYPE_COLOR4  ] = "color4",
Justin M. Forbes a81953
+   [ SPICE_CURSOR_TYPE_COLOR8  ] = "color8",
Justin M. Forbes a81953
+   [ SPICE_CURSOR_TYPE_COLOR16 ] = "color16",
Justin M. Forbes a81953
+   [ SPICE_CURSOR_TYPE_COLOR24 ] = "color24",
Justin M. Forbes a81953
+   [ SPICE_CURSOR_TYPE_COLOR32 ] = "color32",
Justin M. Forbes a81953
+};
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static const char *qxl_v2n(const char *n[], size_t l, int v)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    if (v >= l || !n[v])
Justin M. Forbes a81953
+        return "???";
Justin M. Forbes a81953
+    return n[v];
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+#define qxl_name(_list, _value) qxl_v2n(_list, ARRAY_SIZE(_list), _value)
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void qxl_log_cmd_draw(PCIQXLDevice *qxl, QXLDrawable *draw)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    fprintf(stderr, ": surface_id %d type %s effect %s",
Justin M. Forbes a81953
+            draw->surface_id,
Justin M. Forbes a81953
+            qxl_name(qxl_draw_type, draw->type),
Justin M. Forbes a81953
+            qxl_name(qxl_draw_effect, draw->effect));
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void qxl_log_cmd_draw_compat(PCIQXLDevice *qxl, QXLCompatDrawable *draw)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    fprintf(stderr, ": type %s effect %s",
Justin M. Forbes a81953
+            qxl_name(qxl_draw_type, draw->type),
Justin M. Forbes a81953
+            qxl_name(qxl_draw_effect, draw->effect));
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void qxl_log_cmd_surface(PCIQXLDevice *qxl, QXLSurfaceCmd *cmd)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    fprintf(stderr, ": %s id %d",
Justin M. Forbes a81953
+            qxl_name(qxl_surface_cmd, cmd->type),
Justin M. Forbes a81953
+            cmd->surface_id);
Justin M. Forbes a81953
+    if (cmd->type == QXL_SURFACE_CMD_CREATE) {
Justin M. Forbes a81953
+        fprintf(stderr, " size %dx%d stride %d format %s (count %d, max %d)",
Justin M. Forbes a81953
+                cmd->u.surface_create.width,
Justin M. Forbes a81953
+                cmd->u.surface_create.height,
Justin M. Forbes a81953
+                cmd->u.surface_create.stride,
Justin M. Forbes a81953
+                qxl_name(spice_surface_fmt, cmd->u.surface_create.format),
Justin M. Forbes a81953
+                qxl->guest_surfaces.count, qxl->guest_surfaces.max);
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+    if (cmd->type == QXL_SURFACE_CMD_DESTROY) {
Justin M. Forbes a81953
+        fprintf(stderr, " (count %d)", qxl->guest_surfaces.count);
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+void qxl_log_cmd_cursor(PCIQXLDevice *qxl, QXLCursorCmd *cmd, int group_id)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    QXLCursor *cursor;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    fprintf(stderr, ": %s",
Justin M. Forbes a81953
+            qxl_name(qxl_cursor_cmd, cmd->type));
Justin M. Forbes a81953
+    switch (cmd->type) {
Justin M. Forbes a81953
+    case QXL_CURSOR_SET:
Justin M. Forbes a81953
+        fprintf(stderr, " +%d+%d visible %s, shape @ 0x%" PRIx64,
Justin M. Forbes a81953
+                cmd->u.set.position.x,
Justin M. Forbes a81953
+                cmd->u.set.position.y,
Justin M. Forbes a81953
+                cmd->u.set.visible ? "yes" : "no",
Justin M. Forbes a81953
+                cmd->u.set.shape);
Justin M. Forbes a81953
+        cursor = qxl_phys2virt(qxl, cmd->u.set.shape, group_id);
Justin M. Forbes a81953
+        fprintf(stderr, " type %s size %dx%d hot-spot +%d+%d"
Justin M. Forbes a81953
+                " unique 0x%" PRIx64 " data-size %d",
Justin M. Forbes a81953
+                qxl_name(spice_cursor_type, cursor->header.type),
Justin M. Forbes a81953
+                cursor->header.width, cursor->header.height,
Justin M. Forbes a81953
+                cursor->header.hot_spot_x, cursor->header.hot_spot_y,
Justin M. Forbes a81953
+                cursor->header.unique, cursor->data_size);
Justin M. Forbes a81953
+        break;
Justin M. Forbes a81953
+    case QXL_CURSOR_MOVE:
Justin M. Forbes a81953
+        fprintf(stderr, " +%d+%d", cmd->u.position.x, cmd->u.position.y);
Justin M. Forbes a81953
+        break;
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+void qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    bool compat = ext->flags & QXL_COMMAND_FLAG_COMPAT;
Justin M. Forbes a81953
+    void *data;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    if (!qxl->cmdlog) {
Justin M. Forbes a81953
+        return;
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+    fprintf(stderr, "qxl-%d/%s:", qxl->id, ring);
Justin M. Forbes a81953
+    fprintf(stderr, " cmd @ 0x%" PRIx64 " %s%s", ext->cmd.data,
Justin M. Forbes a81953
+            qxl_name(qxl_type, ext->cmd.type),
Justin M. Forbes a81953
+            compat ? "(compat)" : "");
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    data = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
Justin M. Forbes a81953
+    switch (ext->cmd.type) {
Justin M. Forbes a81953
+    case QXL_CMD_DRAW:
Justin M. Forbes a81953
+        if (!compat) {
Justin M. Forbes a81953
+            qxl_log_cmd_draw(qxl, data);
Justin M. Forbes a81953
+        } else {
Justin M. Forbes a81953
+            qxl_log_cmd_draw_compat(qxl, data);
Justin M. Forbes a81953
+        }
Justin M. Forbes a81953
+        break;
Justin M. Forbes a81953
+    case QXL_CMD_SURFACE:
Justin M. Forbes a81953
+        qxl_log_cmd_surface(qxl, data);
Justin M. Forbes a81953
+        break;
Justin M. Forbes a81953
+    case QXL_CMD_CURSOR:
Justin M. Forbes a81953
+        qxl_log_cmd_cursor(qxl, data, ext->group_id);
Justin M. Forbes a81953
+        break;
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+    fprintf(stderr, "\n");
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
diff --git a/hw/qxl-render.c b/hw/qxl-render.c
Justin M. Forbes a81953
new file mode 100644
Justin M. Forbes a81953
index 0000000..d9ebca4
Justin M. Forbes a81953
--- /dev/null
Justin M. Forbes a81953
+++ b/hw/qxl-render.c
Justin M. Forbes a81953
@@ -0,0 +1,207 @@
Justin M. Forbes a81953
+/*
Justin M. Forbes a81953
+ * qxl local rendering (aka display on sdl/vnc)
Justin M. Forbes a81953
+ */
Justin M. Forbes a81953
+#include <stdio.h>
Justin M. Forbes a81953
+#include <stdbool.h>
Justin M. Forbes a81953
+#include <stdint.h>
Justin M. Forbes a81953
+#include <string.h>
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+#include "qxl.h"
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void qxl_flip(PCIQXLDevice *qxl, QXLRect *rect)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    uint8_t *src = qxl->guest_primary.data;
Justin M. Forbes a81953
+    uint8_t *dst = qxl->guest_primary.flipped;
Justin M. Forbes a81953
+    int len, i;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    src += (qxl->guest_primary.surface.height - rect->top - 1) *
Justin M. Forbes a81953
+        qxl->guest_primary.stride;
Justin M. Forbes a81953
+    dst += rect->top  * qxl->guest_primary.stride;
Justin M. Forbes a81953
+    src += rect->left * qxl->guest_primary.bytes_pp;
Justin M. Forbes a81953
+    dst += rect->left * qxl->guest_primary.bytes_pp;
Justin M. Forbes a81953
+    len  = (rect->right - rect->left) * qxl->guest_primary.bytes_pp;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    for (i = rect->top; i < rect->bottom; i++) {
Justin M. Forbes a81953
+        memcpy(dst, src, len);
Justin M. Forbes a81953
+        dst += qxl->guest_primary.stride;
Justin M. Forbes a81953
+        src -= qxl->guest_primary.stride;
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+void qxl_render_resize(PCIQXLDevice *qxl)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    QXLSurfaceCreate *sc = &qxl->guest_primary.surface;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    qxl->guest_primary.stride = sc->stride;
Justin M. Forbes a81953
+    qxl->guest_primary.resized++;
Justin M. Forbes a81953
+    switch (sc->format) {
Justin M. Forbes a81953
+    case SPICE_SURFACE_FMT_16_555:
Justin M. Forbes a81953
+        qxl->guest_primary.bytes_pp = 2;
Justin M. Forbes a81953
+        qxl->guest_primary.bits_pp = 15;
Justin M. Forbes a81953
+        break;
Justin M. Forbes a81953
+    case SPICE_SURFACE_FMT_16_565:
Justin M. Forbes a81953
+        qxl->guest_primary.bytes_pp = 2;
Justin M. Forbes a81953
+        qxl->guest_primary.bits_pp = 16;
Justin M. Forbes a81953
+        break;
Justin M. Forbes a81953
+    case SPICE_SURFACE_FMT_32_xRGB:
Justin M. Forbes a81953
+    case SPICE_SURFACE_FMT_32_ARGB:
Justin M. Forbes a81953
+        qxl->guest_primary.bytes_pp = 4;
Justin M. Forbes a81953
+        qxl->guest_primary.bits_pp = 32;
Justin M. Forbes a81953
+        break;
Justin M. Forbes a81953
+    default:
Justin M. Forbes a81953
+        fprintf(stderr, "%s: unhandled format: %x\n", __FUNCTION__,
Justin M. Forbes a81953
+                qxl->guest_primary.surface.format);
Justin M. Forbes a81953
+        qxl->guest_primary.bytes_pp = 4;
Justin M. Forbes a81953
+        qxl->guest_primary.bits_pp = 32;
Justin M. Forbes a81953
+        break;
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+void qxl_render_update(PCIQXLDevice *qxl)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    VGACommonState *vga = &qxl->vga;
Justin M. Forbes a81953
+    QXLRect dirty[32], update;
Justin M. Forbes a81953
+    void *ptr;
Justin M. Forbes a81953
+    int i;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    if (qxl->guest_primary.resized) {
Justin M. Forbes a81953
+        qxl->guest_primary.resized = 0;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+        if (qxl->guest_primary.flipped) {
Justin M. Forbes a81953
+            qemu_free(qxl->guest_primary.flipped);
Justin M. Forbes a81953
+            qxl->guest_primary.flipped = NULL;
Justin M. Forbes a81953
+        }
Justin M. Forbes a81953
+        qemu_free_displaysurface(vga->ds);
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+        qxl->guest_primary.data = qemu_get_ram_ptr(qxl->vga.vram_offset);
Justin M. Forbes a81953
+        if (qxl->guest_primary.stride < 0) {
Justin M. Forbes a81953
+            /* spice surface is upside down -> need extra buffer to flip */
Justin M. Forbes a81953
+            qxl->guest_primary.stride = -qxl->guest_primary.stride;
Justin M. Forbes a81953
+            qxl->guest_primary.flipped = qemu_malloc(qxl->guest_primary.surface.width *
Justin M. Forbes a81953
+                                                     qxl->guest_primary.stride);
Justin M. Forbes a81953
+            ptr = qxl->guest_primary.flipped;
Justin M. Forbes a81953
+        } else {
Justin M. Forbes a81953
+            ptr = qxl->guest_primary.data;
Justin M. Forbes a81953
+        }
Justin M. Forbes a81953
+        fprintf(stderr, "%s: %dx%d, stride %d, bpp %d, depth %d, flip %s\n",
Justin M. Forbes a81953
+                __FUNCTION__,
Justin M. Forbes a81953
+                qxl->guest_primary.surface.width,
Justin M. Forbes a81953
+                qxl->guest_primary.surface.height,
Justin M. Forbes a81953
+                qxl->guest_primary.stride,
Justin M. Forbes a81953
+                qxl->guest_primary.bytes_pp,
Justin M. Forbes a81953
+                qxl->guest_primary.bits_pp,
Justin M. Forbes a81953
+                qxl->guest_primary.flipped ? "yes" : "no");
Justin M. Forbes a81953
+        vga->ds->surface =
Justin M. Forbes a81953
+            qemu_create_displaysurface_from(qxl->guest_primary.surface.width,
Justin M. Forbes a81953
+                                            qxl->guest_primary.surface.height,
Justin M. Forbes a81953
+                                            qxl->guest_primary.bits_pp,
Justin M. Forbes a81953
+                                            qxl->guest_primary.stride,
Justin M. Forbes a81953
+                                            ptr);
Justin M. Forbes a81953
+        dpy_resize(vga->ds);
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    if (!qxl->guest_primary.commands)
Justin M. Forbes a81953
+        return;
Justin M. Forbes a81953
+    qxl->guest_primary.commands = 0;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    update.left   = 0;
Justin M. Forbes a81953
+    update.right  = qxl->guest_primary.surface.width;
Justin M. Forbes a81953
+    update.top    = 0;
Justin M. Forbes a81953
+    update.bottom = qxl->guest_primary.surface.height;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    memset(dirty, 0, sizeof(dirty));
Justin M. Forbes a81953
+    qxl->ssd.worker->update_area(qxl->ssd.worker, 0, &update,
Justin M. Forbes a81953
+                                 dirty, ARRAY_SIZE(dirty), 1);
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    for (i = 0; i < ARRAY_SIZE(dirty); i++) {
Justin M. Forbes a81953
+        if (qemu_spice_rect_is_empty(dirty+i))
Justin M. Forbes a81953
+            break;
Justin M. Forbes a81953
+        if (qxl->guest_primary.flipped) {
Justin M. Forbes a81953
+            qxl_flip(qxl, dirty+i);
Justin M. Forbes a81953
+        }
Justin M. Forbes a81953
+        dpy_update(vga->ds,
Justin M. Forbes a81953
+                   dirty[i].left, dirty[i].top,
Justin M. Forbes a81953
+                   dirty[i].right - dirty[i].left,
Justin M. Forbes a81953
+                   dirty[i].bottom - dirty[i].top);
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static QEMUCursor *qxl_cursor(PCIQXLDevice *qxl, QXLCursor *cursor)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    QEMUCursor *c;
Justin M. Forbes a81953
+    uint8_t *image, *mask;
Justin M. Forbes a81953
+    int size;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    c = cursor_alloc(cursor->header.width, cursor->header.height);
Justin M. Forbes a81953
+    c->hot_x = cursor->header.hot_spot_x;
Justin M. Forbes a81953
+    c->hot_y = cursor->header.hot_spot_y;
Justin M. Forbes a81953
+    switch (cursor->header.type) {
Justin M. Forbes a81953
+    case SPICE_CURSOR_TYPE_ALPHA:
Justin M. Forbes a81953
+        size = cursor->header.width * cursor->header.height * sizeof(uint32_t);
Justin M. Forbes a81953
+        memcpy(c->data, cursor->chunk.data, size);
Justin M. Forbes a81953
+        if (qxl->debug > 1)
Justin M. Forbes a81953
+            cursor_print_ascii_art(c, "qxl/alpha");
Justin M. Forbes a81953
+        break;
Justin M. Forbes a81953
+    case SPICE_CURSOR_TYPE_MONO:
Justin M. Forbes a81953
+        mask  = cursor->chunk.data;
Justin M. Forbes a81953
+        image = mask + cursor_get_mono_bpl(c) * c->width;
Justin M. Forbes a81953
+        cursor_set_mono(c, 0xffffff, 0x000000, image, 1, mask);
Justin M. Forbes a81953
+        if (qxl->debug > 1)
Justin M. Forbes a81953
+            cursor_print_ascii_art(c, "qxl/mono");
Justin M. Forbes a81953
+        break;
Justin M. Forbes a81953
+    default:
Justin M. Forbes a81953
+        fprintf(stderr, "%s: not implemented: type %d\n",
Justin M. Forbes a81953
+                __FUNCTION__, cursor->header.type);
Justin M. Forbes a81953
+        goto fail;
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+    return c;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+fail:
Justin M. Forbes a81953
+    cursor_put(c);
Justin M. Forbes a81953
+    return NULL;
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+void qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
Justin M. Forbes a81953
+    QXLCursor *cursor;
Justin M. Forbes a81953
+    QEMUCursor *c;
Justin M. Forbes a81953
+    int x = -1, y = -1;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    if (!qxl->ssd.ds->mouse_set ||
Justin M. Forbes a81953
+        !qxl->ssd.ds->cursor_define)
Justin M. Forbes a81953
+        return;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+#if 1
Justin M. Forbes a81953
+    if (cmd->type != QXL_CURSOR_MOVE) {
Justin M. Forbes a81953
+        fprintf(stderr, "%s", __FUNCTION__);
Justin M. Forbes a81953
+        qxl_log_cmd_cursor(qxl, cmd, ext->group_id);
Justin M. Forbes a81953
+        fprintf(stderr, "\n");
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+#endif
Justin M. Forbes a81953
+    switch (cmd->type) {
Justin M. Forbes a81953
+    case QXL_CURSOR_SET:
Justin M. Forbes a81953
+        x = cmd->u.set.position.x;
Justin M. Forbes a81953
+        y = cmd->u.set.position.y;
Justin M. Forbes a81953
+        cursor = qxl_phys2virt(qxl, cmd->u.set.shape, ext->group_id);
Justin M. Forbes a81953
+        if (cursor->chunk.data_size != cursor->data_size) {
Justin M. Forbes a81953
+            fprintf(stderr, "%s: multiple chunks\n", __FUNCTION__);
Justin M. Forbes a81953
+            return;
Justin M. Forbes a81953
+        }
Justin M. Forbes a81953
+        c = qxl_cursor(qxl, cursor);
Justin M. Forbes a81953
+        if (c == NULL) {
Justin M. Forbes a81953
+            c = cursor_builtin_left_ptr();
Justin M. Forbes a81953
+        }
Justin M. Forbes a81953
+        qxl->ssd.ds->cursor_define(c);
Justin M. Forbes a81953
+        cursor_put(c);
Justin M. Forbes a81953
+        break;
Justin M. Forbes a81953
+    case QXL_CURSOR_MOVE:
Justin M. Forbes a81953
+        x = cmd->u.position.x;
Justin M. Forbes a81953
+        y = cmd->u.position.y;
Justin M. Forbes a81953
+        break;
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+    if (x != -1 && y != -1) {
Justin M. Forbes a81953
+        qxl->ssd.ds->mouse_set(x, y, 1);
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
diff --git a/hw/qxl.c b/hw/qxl.c
Justin M. Forbes a81953
new file mode 100644
Justin M. Forbes a81953
index 0000000..475360c
Justin M. Forbes a81953
--- /dev/null
Justin M. Forbes a81953
+++ b/hw/qxl.c
Justin M. Forbes a81953
@@ -0,0 +1,1411 @@
Justin M. Forbes a81953
+#include <stdio.h>
Justin M. Forbes a81953
+#include <stdlib.h>
Justin M. Forbes a81953
+#include <stdbool.h>
Justin M. Forbes a81953
+#include <stdint.h>
Justin M. Forbes a81953
+#include <string.h>
Justin M. Forbes a81953
+#include <pthread.h>
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+#include "qemu-common.h"
Justin M. Forbes a81953
+#include "qemu-timer.h"
Justin M. Forbes a81953
+#include "qemu-queue.h"
Justin M. Forbes a81953
+#include "monitor.h"
Justin M. Forbes a81953
+#include "sysemu.h"
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+#include "qxl.h"
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+#undef SPICE_RING_PROD_ITEM
Justin M. Forbes a81953
+#define SPICE_RING_PROD_ITEM(r, ret) {                                  \
Justin M. Forbes a81953
+        typeof(r) start = r;                                            \
Justin M. Forbes a81953
+        typeof(r) end = r + 1;                                          \
Justin M. Forbes a81953
+        uint32_t prod = (r)->prod & SPICE_RING_INDEX_MASK(r);           \
Justin M. Forbes a81953
+        typeof(&(r)->items[prod]) m_item = &(r)->items[prod];           \
Justin M. Forbes a81953
+        if (!((uint8_t*)m_item >= (uint8_t*)(start) && (uint8_t*)(m_item + 1) <= (uint8_t*)(end))) { \
Justin M. Forbes a81953
+            abort();                                                    \
Justin M. Forbes a81953
+        }                                                               \
Justin M. Forbes a81953
+        ret = &m_item->el;                                              \
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+#undef SPICE_RING_CONS_ITEM
Justin M. Forbes a81953
+#define SPICE_RING_CONS_ITEM(r, ret) {                                  \
Justin M. Forbes a81953
+        typeof(r) start = r;                                            \
Justin M. Forbes a81953
+        typeof(r) end = r + 1;                                          \
Justin M. Forbes a81953
+        uint32_t cons = (r)->cons & SPICE_RING_INDEX_MASK(r);           \
Justin M. Forbes a81953
+        typeof(&(r)->items[cons]) m_item = &(r)->items[cons];           \
Justin M. Forbes a81953
+        if (!((uint8_t*)m_item >= (uint8_t*)(start) && (uint8_t*)(m_item + 1) <= (uint8_t*)(end))) { \
Justin M. Forbes a81953
+            abort();                                                    \
Justin M. Forbes a81953
+        }                                                               \
Justin M. Forbes a81953
+        ret = &m_item->el;                                              \
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+#undef ALIGN
Justin M. Forbes a81953
+#define ALIGN(a, b) (((a) + ((b) - 1)) & ~((b) - 1))
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+#define PIXEL_SIZE 0.2936875 //1280x1024 is 14.8" x 11.9" 
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+#define QXL_MODE(_x, _y, _b, _o)                  \
Justin M. Forbes a81953
+    {   .x_res = _x,                              \
Justin M. Forbes a81953
+        .y_res = _y,                              \
Justin M. Forbes a81953
+        .bits  = _b,                              \
Justin M. Forbes a81953
+        .stride = (_x) * (_b) / 8,                \
Justin M. Forbes a81953
+        .x_mili = PIXEL_SIZE * (_x),              \
Justin M. Forbes a81953
+        .y_mili = PIXEL_SIZE * (_y),              \
Justin M. Forbes a81953
+        .orientation = _o,                        \
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+#define QXL_MODE_16_32(x_res, y_res, orientation) \
Justin M. Forbes a81953
+    QXL_MODE(x_res, y_res, 16, orientation),      \
Justin M. Forbes a81953
+    QXL_MODE(x_res, y_res, 32, orientation)
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+#define QXL_MODE_EX(x_res, y_res)                 \
Justin M. Forbes a81953
+    QXL_MODE_16_32(x_res, y_res, 0),              \
Justin M. Forbes a81953
+    QXL_MODE_16_32(y_res, x_res, 1),              \
Justin M. Forbes a81953
+    QXL_MODE_16_32(x_res, y_res, 2),              \
Justin M. Forbes a81953
+    QXL_MODE_16_32(y_res, x_res, 3)
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static QXLMode qxl_modes[] = {
Justin M. Forbes a81953
+    QXL_MODE_EX(640, 480),
Justin M. Forbes a81953
+    QXL_MODE_EX(800, 600),
Justin M. Forbes a81953
+    QXL_MODE_EX(832, 624),
Justin M. Forbes a81953
+    QXL_MODE_EX(1024, 768),
Justin M. Forbes a81953
+    QXL_MODE_EX(1152, 864),
Justin M. Forbes a81953
+    QXL_MODE_EX(1152, 870),
Justin M. Forbes a81953
+    QXL_MODE_EX(1280, 720),
Justin M. Forbes a81953
+    QXL_MODE_EX(1280, 768),
Justin M. Forbes a81953
+    QXL_MODE_EX(1280, 800),
Justin M. Forbes a81953
+    QXL_MODE_EX(1280, 960),
Justin M. Forbes a81953
+    QXL_MODE_EX(1280, 1024),
Justin M. Forbes a81953
+    QXL_MODE_EX(1360, 768),
Justin M. Forbes a81953
+    QXL_MODE_EX(1366, 768),
Justin M. Forbes a81953
+    QXL_MODE_EX(1400, 1050),
Justin M. Forbes a81953
+    QXL_MODE_EX(1440, 900),
Justin M. Forbes a81953
+    QXL_MODE_EX(1600, 900),
Justin M. Forbes a81953
+    QXL_MODE_EX(1600, 1200),
Justin M. Forbes a81953
+    QXL_MODE_EX(1680, 1050),
Justin M. Forbes a81953
+    QXL_MODE_EX(1920, 1080),
Justin M. Forbes a81953
+#ifdef QXL_HIRES_MODES
Justin M. Forbes a81953
+    QXL_MODE_EX(1920, 1200),
Justin M. Forbes a81953
+    QXL_MODE_EX(1920, 1440),
Justin M. Forbes a81953
+    QXL_MODE_EX(2048, 1536),
Justin M. Forbes a81953
+    QXL_MODE_EX(2560, 1600),
Justin M. Forbes a81953
+    QXL_MODE_EX(2560, 2048),
Justin M. Forbes a81953
+    QXL_MODE_EX(2800, 2100),
Justin M. Forbes a81953
+    QXL_MODE_EX(3200, 2400),
Justin M. Forbes a81953
+#endif
Justin M. Forbes a81953
+};
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static int device_id = 0;
Justin M. Forbes a81953
+static PCIQXLDevice *qxl0;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void qxl_send_events(PCIQXLDevice *d, uint32_t events);
Justin M. Forbes a81953
+static void qxl_destroy_primary(PCIQXLDevice *d);
Justin M. Forbes a81953
+static void qxl_reset_memslots(PCIQXLDevice *d);
Justin M. Forbes a81953
+static void qxl_reset_surfaces(PCIQXLDevice *d);
Justin M. Forbes a81953
+static void qxl_ring_set_dirty(PCIQXLDevice *qxl);
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static inline uint32_t msb_mask(uint32_t val)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    uint32_t mask;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    do {
Justin M. Forbes a81953
+        mask = ~(val - 1) & val;
Justin M. Forbes a81953
+        val &= ~mask;
Justin M. Forbes a81953
+    } while (mask < val);
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    return mask;
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static ram_addr_t qxl_rom_size(void)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    uint32_t rom_size = sizeof(QXLRom) + sizeof(QXLModes) + sizeof(qxl_modes);
Justin M. Forbes a81953
+    rom_size = MAX(rom_size, TARGET_PAGE_SIZE);
Justin M. Forbes a81953
+    rom_size = msb_mask(rom_size * 2 - 1);
Justin M. Forbes a81953
+    return rom_size;
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void init_qxl_rom(PCIQXLDevice *d)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    QXLRom *rom = qemu_get_ram_ptr(d->rom_offset);
Justin M. Forbes a81953
+    QXLModes *modes = (QXLModes *)(rom + 1);
Justin M. Forbes a81953
+    uint32_t ram_header_size;
Justin M. Forbes a81953
+    uint32_t surface0_area_size;
Justin M. Forbes a81953
+    uint32_t num_pages;
Justin M. Forbes a81953
+    uint32_t fb, maxfb = 0;
Justin M. Forbes a81953
+    int i;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    memset(rom, 0, d->rom_size);
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    rom->magic         = cpu_to_le32(QXL_ROM_MAGIC);
Justin M. Forbes a81953
+    rom->id            = cpu_to_le32(d->id);
Justin M. Forbes a81953
+    rom->modes_offset  = cpu_to_le32(sizeof(QXLRom));
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    rom->slot_gen_bits = MEMSLOT_GENERATION_BITS;
Justin M. Forbes a81953
+    rom->slot_id_bits  = MEMSLOT_SLOT_BITS;
Justin M. Forbes a81953
+    rom->slots_start   = 1;
Justin M. Forbes a81953
+    rom->slots_end     = NUM_MEMSLOTS - 1;
Justin M. Forbes a81953
+    rom->n_surfaces    = cpu_to_le32(NUM_SURFACES);
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    modes->n_modes     = cpu_to_le32(ARRAY_SIZE(qxl_modes));
Justin M. Forbes a81953
+    for (i = 0; i < modes->n_modes; i++) {
Justin M. Forbes a81953
+        fb = qxl_modes[i].y_res * qxl_modes[i].stride;
Justin M. Forbes a81953
+        if (maxfb < fb)
Justin M. Forbes a81953
+            maxfb = fb;
Justin M. Forbes a81953
+        modes->modes[i].id          = cpu_to_le32(i);
Justin M. Forbes a81953
+        modes->modes[i].x_res       = cpu_to_le32(qxl_modes[i].x_res);
Justin M. Forbes a81953
+        modes->modes[i].y_res       = cpu_to_le32(qxl_modes[i].y_res);
Justin M. Forbes a81953
+        modes->modes[i].bits        = cpu_to_le32(qxl_modes[i].bits);
Justin M. Forbes a81953
+        modes->modes[i].stride      = cpu_to_le32(qxl_modes[i].stride);
Justin M. Forbes a81953
+        modes->modes[i].x_mili      = cpu_to_le32(qxl_modes[i].x_mili);
Justin M. Forbes a81953
+        modes->modes[i].y_mili      = cpu_to_le32(qxl_modes[i].y_mili);
Justin M. Forbes a81953
+        modes->modes[i].orientation = cpu_to_le32(qxl_modes[i].orientation);
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+    if (maxfb < VGA_RAM_SIZE && d->id == 0)
Justin M. Forbes a81953
+        maxfb = VGA_RAM_SIZE;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    ram_header_size    = ALIGN(sizeof(QXLRam), 4096);
Justin M. Forbes a81953
+    surface0_area_size = ALIGN(maxfb, 4096);
Justin M. Forbes a81953
+    num_pages          = d->vga.vram_size;
Justin M. Forbes a81953
+    num_pages         -= ram_header_size;
Justin M. Forbes a81953
+    num_pages         -= surface0_area_size;
Justin M. Forbes a81953
+    num_pages          = num_pages / TARGET_PAGE_SIZE;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    rom->draw_area_offset   = cpu_to_le32(0);
Justin M. Forbes a81953
+    rom->surface0_area_size = cpu_to_le32(surface0_area_size);
Justin M. Forbes a81953
+    rom->pages_offset       = cpu_to_le32(surface0_area_size);
Justin M. Forbes a81953
+    rom->num_pages          = cpu_to_le32(num_pages);
Justin M. Forbes a81953
+    rom->ram_header_offset  = cpu_to_le32(d->vga.vram_size - ram_header_size);
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    d->shadow_rom = *rom;
Justin M. Forbes a81953
+    d->rom        = rom;
Justin M. Forbes a81953
+    d->modes      = modes;
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void init_qxl_ram(PCIQXLDevice *d)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    uint8_t *buf;
Justin M. Forbes a81953
+    uint64_t *item;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    buf = d->vga.vram_ptr;
Justin M. Forbes a81953
+    d->ram = (QXLRam *)(buf + le32_to_cpu(d->shadow_rom.ram_header_offset));
Justin M. Forbes a81953
+    d->ram->magic       = cpu_to_le32(QXL_RAM_MAGIC);
Justin M. Forbes a81953
+    d->ram->int_pending = cpu_to_le32(0);
Justin M. Forbes a81953
+    d->ram->int_mask    = cpu_to_le32(0);
Justin M. Forbes a81953
+    SPICE_RING_INIT(&d->ram->cmd_ring);
Justin M. Forbes a81953
+    SPICE_RING_INIT(&d->ram->cursor_ring);
Justin M. Forbes a81953
+    SPICE_RING_INIT(&d->ram->release_ring);
Justin M. Forbes a81953
+    SPICE_RING_PROD_ITEM(&d->ram->release_ring, item);
Justin M. Forbes a81953
+    *item = 0;
Justin M. Forbes a81953
+    qxl_ring_set_dirty(d);
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void qxl_set_dirty(ram_addr_t addr, ram_addr_t end)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    while (addr < end) {
Justin M. Forbes a81953
+        cpu_physical_memory_set_dirty(addr);
Justin M. Forbes a81953
+        addr += TARGET_PAGE_SIZE;
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void qxl_rom_set_dirty(PCIQXLDevice *qxl)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    ram_addr_t addr = qxl->rom_offset;
Justin M. Forbes a81953
+    qxl_set_dirty(addr, addr + qxl->rom_size);
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void qxl_ram_set_dirty(PCIQXLDevice *qxl, void *ptr)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    ram_addr_t addr = qxl->vga.vram_offset;
Justin M. Forbes a81953
+    void *base = qxl->vga.vram_ptr;
Justin M. Forbes a81953
+    intptr_t offset;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    offset = ptr - base;
Justin M. Forbes a81953
+    offset &= ~(TARGET_PAGE_SIZE-1);
Justin M. Forbes a81953
+    assert(offset < qxl->vga.vram_size);
Justin M. Forbes a81953
+    qxl_set_dirty(addr + offset, addr + offset + TARGET_PAGE_SIZE);
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void qxl_ring_set_dirty(PCIQXLDevice *qxl)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    ram_addr_t addr = qxl->vga.vram_offset + qxl->shadow_rom.ram_header_offset;
Justin M. Forbes a81953
+    ram_addr_t end  = qxl->vga.vram_offset + qxl->vga.vram_size;
Justin M. Forbes a81953
+    qxl_set_dirty(addr, end);
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+/*
Justin M. Forbes a81953
+ * keep track of some command state, for savevm/loadvm.
Justin M. Forbes a81953
+ */
Justin M. Forbes a81953
+static void qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    switch (le32_to_cpu(ext->cmd.type)) {
Justin M. Forbes a81953
+    case QXL_CMD_SURFACE:
Justin M. Forbes a81953
+    {
Justin M. Forbes a81953
+        QXLSurfaceCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
Justin M. Forbes a81953
+        uint32_t id = le32_to_cpu(cmd->surface_id);
Justin M. Forbes a81953
+        PANIC_ON(id >= NUM_SURFACES);
Justin M. Forbes a81953
+        if (cmd->type == QXL_SURFACE_CMD_CREATE) {
Justin M. Forbes a81953
+            qxl->guest_surfaces.cmds[id] = ext->cmd.data;
Justin M. Forbes a81953
+            qxl->guest_surfaces.count++;
Justin M. Forbes a81953
+            if (qxl->guest_surfaces.max < qxl->guest_surfaces.count)
Justin M. Forbes a81953
+                qxl->guest_surfaces.max = qxl->guest_surfaces.count;
Justin M. Forbes a81953
+        }
Justin M. Forbes a81953
+        if (cmd->type == QXL_SURFACE_CMD_DESTROY) {
Justin M. Forbes a81953
+            qxl->guest_surfaces.cmds[id] = 0;
Justin M. Forbes a81953
+            qxl->guest_surfaces.count--;
Justin M. Forbes a81953
+        }
Justin M. Forbes a81953
+        break;
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+    case QXL_CMD_CURSOR:
Justin M. Forbes a81953
+    {
Justin M. Forbes a81953
+        QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id);
Justin M. Forbes a81953
+        if (cmd->type == QXL_CURSOR_SET) {
Justin M. Forbes a81953
+            qxl->guest_cursor = ext->cmd.data;
Justin M. Forbes a81953
+        }
Justin M. Forbes a81953
+        break;
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+/* spice display interface callbacks */
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void interface_attach_worker(QXLInstance *sin, QXLWorker *qxl_worker)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    dprintf(qxl, 1, "%s:\n", __FUNCTION__);
Justin M. Forbes a81953
+    qxl->ssd.worker = qxl_worker;
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void interface_set_compression_level(QXLInstance *sin, int level)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    dprintf(qxl, 1, "%s: %d\n", __FUNCTION__, level);
Justin M. Forbes a81953
+    qxl->shadow_rom.compression_level = cpu_to_le32(level);
Justin M. Forbes a81953
+    qxl->rom->compression_level = cpu_to_le32(level);
Justin M. Forbes a81953
+    qxl_rom_set_dirty(qxl);
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void interface_set_mm_time(QXLInstance *sin, uint32_t mm_time)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    qxl->shadow_rom.mm_clock = cpu_to_le32(mm_time);
Justin M. Forbes a81953
+    qxl->rom->mm_clock = cpu_to_le32(mm_time);
Justin M. Forbes a81953
+    qxl_rom_set_dirty(qxl);
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    dprintf(qxl, 1, "%s:\n", __FUNCTION__);
Justin M. Forbes a81953
+    info->memslot_gen_bits = MEMSLOT_GENERATION_BITS;
Justin M. Forbes a81953
+    info->memslot_id_bits = MEMSLOT_SLOT_BITS;
Justin M. Forbes a81953
+    info->num_memslots = NUM_MEMSLOTS;
Justin M. Forbes a81953
+    info->num_memslots_groups = NUM_MEMSLOTS_GROUPS;
Justin M. Forbes a81953
+    info->internal_groupslot_id = 0;
Justin M. Forbes a81953
+    info->qxl_ram_size = le32_to_cpu(qxl->shadow_rom.num_pages) << TARGET_PAGE_BITS;
Justin M. Forbes a81953
+    info->n_surfaces = NUM_SURFACES;
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
Justin M. Forbes a81953
+    SimpleSpiceUpdate *update;
Justin M. Forbes a81953
+    QXLCommandRing *ring;
Justin M. Forbes a81953
+    QXLCommand *cmd;
Justin M. Forbes a81953
+    int notify;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    switch (qxl->mode) {
Justin M. Forbes a81953
+    case QXL_MODE_VGA:
Justin M. Forbes a81953
+        dprintf(qxl, 2, "%s: vga\n", __FUNCTION__);
Justin M. Forbes a81953
+        update = qemu_spice_create_update(&qxl->ssd);
Justin M. Forbes a81953
+        if (update == NULL) {
Justin M. Forbes a81953
+            return false;
Justin M. Forbes a81953
+        }
Justin M. Forbes a81953
+        *ext = update->ext;
Justin M. Forbes a81953
+        qxl_log_command(qxl, "vga", ext);
Justin M. Forbes a81953
+        return true;
Justin M. Forbes a81953
+    case QXL_MODE_COMPAT:
Justin M. Forbes a81953
+    case QXL_MODE_NATIVE:
Justin M. Forbes a81953
+    case QXL_MODE_UNDEFINED:
Justin M. Forbes a81953
+        dprintf(qxl, 2, "%s: %s\n", __FUNCTION__,
Justin M. Forbes a81953
+                qxl->cmdflags ? "compat" : "native");
Justin M. Forbes a81953
+        ring = &qxl->ram->cmd_ring;
Justin M. Forbes a81953
+        if (SPICE_RING_IS_EMPTY(ring)) {
Justin M. Forbes a81953
+            return false;
Justin M. Forbes a81953
+        }
Justin M. Forbes a81953
+        SPICE_RING_CONS_ITEM(ring, cmd);
Justin M. Forbes a81953
+        ext->cmd      = *cmd;
Justin M. Forbes a81953
+        ext->group_id = MEMSLOT_GROUP_GUEST;
Justin M. Forbes a81953
+        ext->flags    = qxl->cmdflags;
Justin M. Forbes a81953
+        SPICE_RING_POP(ring, notify);
Justin M. Forbes a81953
+        qxl_ring_set_dirty(qxl);
Justin M. Forbes a81953
+        if (notify) {
Justin M. Forbes a81953
+            qxl_send_events(qxl, QXL_INTERRUPT_DISPLAY);
Justin M. Forbes a81953
+        }
Justin M. Forbes a81953
+        qxl->guest_primary.commands++;
Justin M. Forbes a81953
+        qxl_track_command(qxl, ext);
Justin M. Forbes a81953
+        qxl_log_command(qxl, "cmd", ext);
Justin M. Forbes a81953
+        return true;
Justin M. Forbes a81953
+    default:
Justin M. Forbes a81953
+        return false;
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static int interface_req_cmd_notification(QXLInstance *sin)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
Justin M. Forbes a81953
+    int wait = 1;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    switch (qxl->mode) {
Justin M. Forbes a81953
+    case QXL_MODE_COMPAT:
Justin M. Forbes a81953
+    case QXL_MODE_NATIVE:
Justin M. Forbes a81953
+    case QXL_MODE_UNDEFINED:
Justin M. Forbes a81953
+        SPICE_RING_CONS_WAIT(&qxl->ram->cmd_ring, wait);
Justin M. Forbes a81953
+        qxl_ring_set_dirty(qxl);
Justin M. Forbes a81953
+        break;
Justin M. Forbes a81953
+    default:
Justin M. Forbes a81953
+        /* nothing */
Justin M. Forbes a81953
+        break;
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+    return wait;
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static inline void qxl_push_free_res(PCIQXLDevice *d)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    QXLReleaseRing *ring = &d->ram->release_ring;
Justin M. Forbes a81953
+    uint64_t *item;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+#define QXL_FREE_BUNCH_SIZE 10
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    if (SPICE_RING_IS_EMPTY(ring) || (d->num_free_res == QXL_FREE_BUNCH_SIZE &&
Justin M. Forbes a81953
+                                      ring->prod - ring->cons + 1 != ring->num_items)) {
Justin M. Forbes a81953
+        int notify;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+        SPICE_RING_PUSH(ring, notify);
Justin M. Forbes a81953
+        if (notify) {
Justin M. Forbes a81953
+            qxl_send_events(d, QXL_INTERRUPT_DISPLAY);
Justin M. Forbes a81953
+        }
Justin M. Forbes a81953
+        SPICE_RING_PROD_ITEM(ring, item);
Justin M. Forbes a81953
+        *item = 0;
Justin M. Forbes a81953
+        d->num_free_res = 0;
Justin M. Forbes a81953
+        d->last_release = NULL;
Justin M. Forbes a81953
+        qxl_ring_set_dirty(d);
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void interface_release_resource(QXLInstance *sin,
Justin M. Forbes a81953
+                                       struct QXLReleaseInfoExt ext)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
Justin M. Forbes a81953
+    QXLReleaseRing *ring;
Justin M. Forbes a81953
+    uint64_t *item, id;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    if (ext.group_id == MEMSLOT_GROUP_HOST) {
Justin M. Forbes a81953
+        /* host group -> vga mode update request */
Justin M. Forbes a81953
+        qemu_spice_destroy_update(&qxl->ssd, (void*)ext.info->id);
Justin M. Forbes a81953
+        return;
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    /*
Justin M. Forbes a81953
+     * ext->info points into guest-visible memory
Justin M. Forbes a81953
+     * pci bar 0, $command.release_info
Justin M. Forbes a81953
+     */
Justin M. Forbes a81953
+    ring = &qxl->ram->release_ring;
Justin M. Forbes a81953
+    SPICE_RING_PROD_ITEM(ring, item);
Justin M. Forbes a81953
+    if (*item == 0) {
Justin M. Forbes a81953
+        /* stick head into the ring */
Justin M. Forbes a81953
+        id = ext.info->id;
Justin M. Forbes a81953
+        ext.info->next = 0;
Justin M. Forbes a81953
+        qxl_ram_set_dirty(qxl, &ext.info->next);
Justin M. Forbes a81953
+        *item = id;
Justin M. Forbes a81953
+        qxl_ring_set_dirty(qxl);
Justin M. Forbes a81953
+    } else {
Justin M. Forbes a81953
+        /* append item to the list */
Justin M. Forbes a81953
+        qxl->last_release->next = ext.info->id;
Justin M. Forbes a81953
+        qxl_ram_set_dirty(qxl, &qxl->last_release->next);
Justin M. Forbes a81953
+        ext.info->next = 0;
Justin M. Forbes a81953
+        qxl_ram_set_dirty(qxl, &ext.info->next);
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+    qxl->last_release = ext.info;
Justin M. Forbes a81953
+    qxl->num_free_res++;
Justin M. Forbes a81953
+    qxl_push_free_res(qxl);
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static int interface_get_cursor_command(QXLInstance *sin, struct QXLCommandExt *ext)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
Justin M. Forbes a81953
+    QXLCursorRing *ring;
Justin M. Forbes a81953
+    QXLCommand *cmd;
Justin M. Forbes a81953
+    int notify;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    switch (qxl->mode) {
Justin M. Forbes a81953
+    case QXL_MODE_COMPAT:
Justin M. Forbes a81953
+    case QXL_MODE_NATIVE:
Justin M. Forbes a81953
+    case QXL_MODE_UNDEFINED:
Justin M. Forbes a81953
+        ring = &qxl->ram->cursor_ring;
Justin M. Forbes a81953
+        if (SPICE_RING_IS_EMPTY(ring)) {
Justin M. Forbes a81953
+            return false;
Justin M. Forbes a81953
+        }
Justin M. Forbes a81953
+        SPICE_RING_CONS_ITEM(ring, cmd);
Justin M. Forbes a81953
+        ext->cmd      = *cmd;
Justin M. Forbes a81953
+        ext->group_id = MEMSLOT_GROUP_GUEST;
Justin M. Forbes a81953
+        ext->flags    = qxl->cmdflags;
Justin M. Forbes a81953
+        SPICE_RING_POP(ring, notify);
Justin M. Forbes a81953
+        qxl_ring_set_dirty(qxl);
Justin M. Forbes a81953
+        if (notify) {
Justin M. Forbes a81953
+            qxl_send_events(qxl, QXL_INTERRUPT_CURSOR);
Justin M. Forbes a81953
+        }
Justin M. Forbes a81953
+        qxl->guest_primary.commands++;
Justin M. Forbes a81953
+        qxl_track_command(qxl, ext);
Justin M. Forbes a81953
+        qxl_log_command(qxl, "csr", ext);
Justin M. Forbes a81953
+        if (qxl->id == 0) {
Justin M. Forbes a81953
+            qxl_render_cursor(qxl, ext);
Justin M. Forbes a81953
+        }
Justin M. Forbes a81953
+        return true;
Justin M. Forbes a81953
+    default:
Justin M. Forbes a81953
+        return false;
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static int interface_req_cursor_notification(QXLInstance *sin)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
Justin M. Forbes a81953
+    int wait = 1;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    switch (qxl->mode) {
Justin M. Forbes a81953
+    case QXL_MODE_COMPAT:
Justin M. Forbes a81953
+    case QXL_MODE_NATIVE:
Justin M. Forbes a81953
+    case QXL_MODE_UNDEFINED:
Justin M. Forbes a81953
+        SPICE_RING_CONS_WAIT(&qxl->ram->cursor_ring, wait);
Justin M. Forbes a81953
+        qxl_ring_set_dirty(qxl);
Justin M. Forbes a81953
+        break;
Justin M. Forbes a81953
+    default:
Justin M. Forbes a81953
+        /* nothing */
Justin M. Forbes a81953
+        break;
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+    return wait;
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void interface_notify_update(QXLInstance *sin, uint32_t update_id)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    fprintf(stderr, "%s: abort()\n", __FUNCTION__);
Justin M. Forbes a81953
+    abort();
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static int interface_flush_resources(QXLInstance *sin)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);
Justin M. Forbes a81953
+    int ret;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    ret = qxl->num_free_res;
Justin M. Forbes a81953
+    if (ret) {
Justin M. Forbes a81953
+        qxl_push_free_res(qxl);
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+    return ret;
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static const QXLInterface qxl_interface = {
Justin M. Forbes a81953
+    .base.type               = SPICE_INTERFACE_QXL,
Justin M. Forbes a81953
+    .base.description        = "qxl gpu",
Justin M. Forbes a81953
+    .base.major_version      = SPICE_INTERFACE_QXL_MAJOR,
Justin M. Forbes a81953
+    .base.minor_version      = SPICE_INTERFACE_QXL_MINOR,
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    .pci_vendor              = REDHAT_PCI_VENDOR_ID,
Justin M. Forbes a81953
+    .pci_id                  = QXL_DEVICE_ID,
Justin M. Forbes a81953
+    .pci_revision            = QXL_REVISION,
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    .attache_worker          = interface_attach_worker,
Justin M. Forbes a81953
+    .set_compression_level   = interface_set_compression_level,
Justin M. Forbes a81953
+    .set_mm_time             = interface_set_mm_time,
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    .get_init_info           = interface_get_init_info,
Justin M. Forbes a81953
+    .get_command             = interface_get_command,
Justin M. Forbes a81953
+    .req_cmd_notification    = interface_req_cmd_notification,
Justin M. Forbes a81953
+    .release_resource        = interface_release_resource,
Justin M. Forbes a81953
+    .get_cursor_command      = interface_get_cursor_command,
Justin M. Forbes a81953
+    .req_cursor_notification = interface_req_cursor_notification,
Justin M. Forbes a81953
+    .notify_update           = interface_notify_update,
Justin M. Forbes a81953
+    .flush_resources         = interface_flush_resources,
Justin M. Forbes a81953
+};
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void qxl_enter_vga_mode(PCIQXLDevice *d)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    if (d->mode == QXL_MODE_VGA) {
Justin M. Forbes a81953
+        return;
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+    dprintf(d, 1, "%s\n", __FUNCTION__);
Justin M. Forbes a81953
+    qemu_spice_create_host_primary(&d->ssd);
Justin M. Forbes a81953
+    d->mode = QXL_MODE_VGA;
Justin M. Forbes a81953
+    memset(&d->ssd.dirty, 0, sizeof(d->ssd.dirty));
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void qxl_exit_vga_mode(PCIQXLDevice *d)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    if (d->mode != QXL_MODE_VGA) {
Justin M. Forbes a81953
+        return;
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+    dprintf(d, 1, "%s\n", __FUNCTION__);
Justin M. Forbes a81953
+    qxl_destroy_primary(d);
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void qxl_set_irq(PCIQXLDevice *d)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    uint32_t pending = le32_to_cpu(d->ram->int_pending);
Justin M. Forbes a81953
+    uint32_t mask    = le32_to_cpu(d->ram->int_mask);
Justin M. Forbes a81953
+    int level = !!(pending & mask);
Justin M. Forbes a81953
+    qemu_set_irq(d->pci.irq[0], level);
Justin M. Forbes a81953
+    qxl_ring_set_dirty(d);
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void qxl_write_config(PCIDevice *d, uint32_t address,
Justin M. Forbes a81953
+                             uint32_t val, int len)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, d);
Justin M. Forbes a81953
+    VGACommonState *vga = &qxl->vga;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    if (qxl->id == 0) {
Justin M. Forbes a81953
+        vga_dirty_log_stop(vga);
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+    pci_default_write_config(d, address, val, len);
Justin M. Forbes a81953
+    if (qxl->id == 0) {
Justin M. Forbes a81953
+        if (vga->map_addr && qxl->pci.io_regions[0].addr == -1)
Justin M. Forbes a81953
+            vga->map_addr = 0;
Justin M. Forbes a81953
+        vga_dirty_log_start(vga);
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void qxl_check_state(PCIQXLDevice *d)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    QXLRam *ram = d->ram;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    assert(SPICE_RING_IS_EMPTY(&ram->cmd_ring));
Justin M. Forbes a81953
+    assert(SPICE_RING_IS_EMPTY(&ram->cursor_ring));
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void qxl_reset_state(PCIQXLDevice *d)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    QXLRam *ram = d->ram;
Justin M. Forbes a81953
+    QXLRom *rom = d->rom;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    assert(SPICE_RING_IS_EMPTY(&ram->cmd_ring));
Justin M. Forbes a81953
+    assert(SPICE_RING_IS_EMPTY(&ram->cursor_ring));
Justin M. Forbes a81953
+    d->shadow_rom.update_id = cpu_to_le32(0);
Justin M. Forbes a81953
+    *rom = d->shadow_rom;
Justin M. Forbes a81953
+    qxl_rom_set_dirty(d);
Justin M. Forbes a81953
+    init_qxl_ram(d);
Justin M. Forbes a81953
+    d->num_free_res = 0;
Justin M. Forbes a81953
+    d->last_release = NULL;
Justin M. Forbes a81953
+    memset(&d->ssd.dirty, 0, sizeof(d->ssd.dirty));
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void qxl_soft_reset(PCIQXLDevice *d)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    dprintf(d, 1, "%s:\n", __FUNCTION__);
Justin M. Forbes a81953
+    qxl_check_state(d);
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    if (d->id == 0) {
Justin M. Forbes a81953
+        qxl_enter_vga_mode(d);
Justin M. Forbes a81953
+    } else {
Justin M. Forbes a81953
+        d->mode = QXL_MODE_UNDEFINED;
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void qxl_hard_reset(PCIQXLDevice *d, int loadvm)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    dprintf(d, 1, "%s: start%s\n", __FUNCTION__,
Justin M. Forbes a81953
+            loadvm ? " (loadvm)" : "");
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    d->ssd.worker->reset_cursor(d->ssd.worker);
Justin M. Forbes a81953
+    d->ssd.worker->reset_image_cache(d->ssd.worker);
Justin M. Forbes a81953
+    qxl_reset_surfaces(d);
Justin M. Forbes a81953
+    qxl_reset_memslots(d);
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    /* pre loadvm reset must not touch QXLRam.  This lives in
Justin M. Forbes a81953
+     * device memory, is migrated together with RAM and thus
Justin M. Forbes a81953
+     * already loaded at this point */
Justin M. Forbes a81953
+    if (!loadvm) {
Justin M. Forbes a81953
+        qxl_reset_state(d);
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+    qemu_spice_create_host_memslot(&d->ssd);
Justin M. Forbes a81953
+    qxl_soft_reset(d);
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    dprintf(d, 1, "%s: done\n", __FUNCTION__);
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void qxl_reset_handler(DeviceState *dev)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    PCIQXLDevice *d = DO_UPCAST(PCIQXLDevice, pci.qdev, dev);
Justin M. Forbes a81953
+    qxl_hard_reset(d, 0);
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void qxl_vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    VGACommonState *vga = opaque;
Justin M. Forbes a81953
+    PCIQXLDevice *qxl = container_of(vga, PCIQXLDevice, vga);
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    if (qxl->mode != QXL_MODE_VGA) {
Justin M. Forbes a81953
+        dprintf(qxl, 1, "%s\n", __FUNCTION__);
Justin M. Forbes a81953
+        qxl_destroy_primary(qxl);
Justin M. Forbes a81953
+        qxl_soft_reset(qxl);
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+    vga_ioport_write(opaque, addr, val);
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    static const int regions[] = {
Justin M. Forbes a81953
+        QXL_RAM_RANGE_INDEX,
Justin M. Forbes a81953
+        QXL_VRAM_RANGE_INDEX,
Justin M. Forbes a81953
+    };
Justin M. Forbes a81953
+    uint64_t guest_start;
Justin M. Forbes a81953
+    uint64_t guest_end;
Justin M. Forbes a81953
+    int pci_region;
Justin M. Forbes a81953
+    pcibus_t pci_start;
Justin M. Forbes a81953
+    pcibus_t pci_end;
Justin M. Forbes a81953
+    intptr_t virt_start;
Justin M. Forbes a81953
+    QXLDevMemSlot memslot;
Justin M. Forbes a81953
+    int i;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    guest_start = le64_to_cpu(d->guest_slots[slot_id].slot.mem_start);
Justin M. Forbes a81953
+    guest_end   = le64_to_cpu(d->guest_slots[slot_id].slot.mem_end);
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    dprintf(d, 1, "%s: slot %d: guest phys 0x%" PRIx64 " - 0x%" PRIx64 "\n",
Justin M. Forbes a81953
+            __FUNCTION__, slot_id,
Justin M. Forbes a81953
+            guest_start, guest_end);
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    PANIC_ON(slot_id >= NUM_MEMSLOTS);
Justin M. Forbes a81953
+    PANIC_ON(guest_start > guest_end);
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    for (i = 0; i < ARRAY_SIZE(regions); i++) {
Justin M. Forbes a81953
+        pci_region = regions[i];
Justin M. Forbes a81953
+        pci_start = d->pci.io_regions[pci_region].addr;
Justin M. Forbes a81953
+        pci_end = pci_start + d->pci.io_regions[pci_region].size;
Justin M. Forbes a81953
+        /* mapped? */
Justin M. Forbes a81953
+        if (pci_start == -1) {
Justin M. Forbes a81953
+            continue;
Justin M. Forbes a81953
+        }
Justin M. Forbes a81953
+        /* start address in range ? */
Justin M. Forbes a81953
+        if (guest_start < pci_start || guest_start > pci_end) {
Justin M. Forbes a81953
+            continue;
Justin M. Forbes a81953
+        }
Justin M. Forbes a81953
+        /* end address in range ? */
Justin M. Forbes a81953
+        if (guest_end > pci_end) {
Justin M. Forbes a81953
+            continue;
Justin M. Forbes a81953
+        }
Justin M. Forbes a81953
+        /* passed */
Justin M. Forbes a81953
+        break;
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+    PANIC_ON(i == ARRAY_SIZE(regions)); /* finished loop without match */
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    switch (pci_region) {
Justin M. Forbes a81953
+    case QXL_RAM_RANGE_INDEX:
Justin M. Forbes a81953
+        virt_start = (intptr_t)qemu_get_ram_ptr(d->vga.vram_offset);
Justin M. Forbes a81953
+        break;
Justin M. Forbes a81953
+    case QXL_VRAM_RANGE_INDEX:
Justin M. Forbes a81953
+        virt_start = (intptr_t)qemu_get_ram_ptr(d->vram_offset);
Justin M. Forbes a81953
+        break;
Justin M. Forbes a81953
+    default:
Justin M. Forbes a81953
+        /* should not happen */
Justin M. Forbes a81953
+        abort();
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    memslot.slot_id = slot_id;
Justin M. Forbes a81953
+    memslot.slot_group_id = MEMSLOT_GROUP_GUEST; /* guest group */
Justin M. Forbes a81953
+    memslot.virt_start = virt_start + (guest_start - pci_start);
Justin M. Forbes a81953
+    memslot.virt_end   = virt_start + (guest_end   - pci_start);
Justin M. Forbes a81953
+    memslot.addr_delta = memslot.virt_start - delta;
Justin M. Forbes a81953
+    memslot.generation = d->rom->slot_generation = 0; // FIXME d->generation++;
Justin M. Forbes a81953
+    qxl_rom_set_dirty(d);
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    dprintf(d, 1, "%s: slot %d: host virt 0x%" PRIx64 " - 0x%" PRIx64 "\n",
Justin M. Forbes a81953
+            __FUNCTION__, memslot.slot_id,
Justin M. Forbes a81953
+            memslot.virt_start, memslot.virt_end);
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    d->ssd.worker->add_memslot(d->ssd.worker, &memslot);
Justin M. Forbes a81953
+    d->guest_slots[slot_id].ptr = (void*)memslot.virt_start;
Justin M. Forbes a81953
+    d->guest_slots[slot_id].size = memslot.virt_end - memslot.virt_start;
Justin M. Forbes a81953
+    d->guest_slots[slot_id].delta = delta;
Justin M. Forbes a81953
+    d->guest_slots[slot_id].active = 1;
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void qxl_del_memslot(PCIQXLDevice *d, uint32_t slot_id)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    dprintf(d, 1, "%s: slot %d\n", __FUNCTION__, slot_id);
Justin M. Forbes a81953
+    d->ssd.worker->del_memslot(d->ssd.worker, MEMSLOT_GROUP_HOST, slot_id);
Justin M. Forbes a81953
+    d->guest_slots[slot_id].active = 0;
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void qxl_reset_memslots(PCIQXLDevice *d)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    dprintf(d, 1, "%s:\n", __FUNCTION__);
Justin M. Forbes a81953
+    d->ssd.worker->reset_memslots(d->ssd.worker);
Justin M. Forbes a81953
+    memset(&d->guest_slots, 0, sizeof(d->guest_slots));
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void qxl_reset_surfaces(PCIQXLDevice *d)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    dprintf(d, 1, "%s:\n", __FUNCTION__);
Justin M. Forbes a81953
+    d->mode = QXL_MODE_UNDEFINED;
Justin M. Forbes a81953
+    d->ssd.worker->destroy_surfaces(d->ssd.worker);
Justin M. Forbes a81953
+    memset(&d->guest_surfaces.cmds, 0, sizeof(d->guest_surfaces.cmds));
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    uint64_t phys   = le64_to_cpu(pqxl);
Justin M. Forbes a81953
+    uint32_t slot   = (phys >> (64 -  8)) & 0xff;
Justin M. Forbes a81953
+    uint64_t offset = phys & 0xffffffffffff;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    switch (group_id) {
Justin M. Forbes a81953
+    case MEMSLOT_GROUP_HOST:
Justin M. Forbes a81953
+        return (void*)offset;
Justin M. Forbes a81953
+    case MEMSLOT_GROUP_GUEST:
Justin M. Forbes a81953
+        PANIC_ON(slot > NUM_MEMSLOTS);
Justin M. Forbes a81953
+        PANIC_ON(!qxl->guest_slots[slot].active);
Justin M. Forbes a81953
+        PANIC_ON(offset < qxl->guest_slots[slot].delta);
Justin M. Forbes a81953
+        offset -= qxl->guest_slots[slot].delta;
Justin M. Forbes a81953
+        PANIC_ON(offset > qxl->guest_slots[slot].size)
Justin M. Forbes a81953
+        return qxl->guest_slots[slot].ptr + offset;
Justin M. Forbes a81953
+    default:
Justin M. Forbes a81953
+        PANIC_ON(1);
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    QXLDevSurfaceCreate surface;
Justin M. Forbes a81953
+    QXLSurfaceCreate *sc = &qxl->guest_primary.surface;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    assert(qxl->mode != QXL_MODE_NATIVE);
Justin M. Forbes a81953
+    qxl_exit_vga_mode(qxl);
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    dprintf(qxl, 1, "%s: %dx%d\n", __FUNCTION__,
Justin M. Forbes a81953
+            le32_to_cpu(sc->width), le32_to_cpu(sc->height));
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    surface.format     = le32_to_cpu(sc->format);
Justin M. Forbes a81953
+    surface.height     = le32_to_cpu(sc->height);
Justin M. Forbes a81953
+    surface.mem        = le64_to_cpu(sc->mem);
Justin M. Forbes a81953
+    surface.position   = le32_to_cpu(sc->position);
Justin M. Forbes a81953
+    surface.stride     = le32_to_cpu(sc->stride);
Justin M. Forbes a81953
+    surface.width      = le32_to_cpu(sc->width);
Justin M. Forbes a81953
+    surface.type       = le32_to_cpu(sc->type);
Justin M. Forbes a81953
+    surface.flags      = le32_to_cpu(sc->flags);
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    surface.mouse_mode = true;
Justin M. Forbes a81953
+    surface.group_id   = MEMSLOT_GROUP_GUEST;
Justin M. Forbes a81953
+    if (loadvm) {
Justin M. Forbes a81953
+        surface.flags |= QXL_SURF_FLAG_KEEP_DATA;
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    qxl->mode = QXL_MODE_NATIVE;
Justin M. Forbes a81953
+    qxl->cmdflags = 0;
Justin M. Forbes a81953
+    qxl->ssd.worker->create_primary_surface(qxl->ssd.worker, 0, &surface);
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    /* for local rendering */
Justin M. Forbes a81953
+    qxl_render_resize(qxl);
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void qxl_destroy_primary(PCIQXLDevice *d)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    if (d->mode == QXL_MODE_UNDEFINED) {
Justin M. Forbes a81953
+        return;
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    dprintf(d, 1, "%s\n", __FUNCTION__);
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    d->mode = QXL_MODE_UNDEFINED;
Justin M. Forbes a81953
+    d->ssd.worker->destroy_primary_surface(d->ssd.worker, 0);
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void qxl_set_mode(PCIQXLDevice *d, int modenr)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    pcibus_t start = d->pci.io_regions[QXL_RAM_RANGE_INDEX].addr;
Justin M. Forbes a81953
+    pcibus_t end   = d->pci.io_regions[QXL_RAM_RANGE_INDEX].size + start;
Justin M. Forbes a81953
+    QXLMode *mode = d->modes->modes + modenr;
Justin M. Forbes a81953
+    uint64_t devmem = d->pci.io_regions[QXL_RAM_RANGE_INDEX].addr;
Justin M. Forbes a81953
+    QXLMemSlot slot = {
Justin M. Forbes a81953
+        .mem_start = start,
Justin M. Forbes a81953
+        .mem_end = end
Justin M. Forbes a81953
+    };
Justin M. Forbes a81953
+    QXLSurfaceCreate surface = {
Justin M. Forbes a81953
+        .width      = mode->x_res,
Justin M. Forbes a81953
+        .height     = mode->y_res,
Justin M. Forbes a81953
+        .stride     = -mode->x_res * 4,
Justin M. Forbes a81953
+        .format     = SPICE_SURFACE_FMT_32_xRGB,
Justin M. Forbes a81953
+        .mouse_mode = true,
Justin M. Forbes a81953
+        .mem        = devmem,
Justin M. Forbes a81953
+    };
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    dprintf(d, 1, "%s: mode %d  [ %d x %d @ %d bpp devmem 0x%lx ]\n", __FUNCTION__,
Justin M. Forbes a81953
+            modenr, mode->x_res, mode->y_res, mode->bits, devmem);
Justin M. Forbes a81953
+    qxl_hard_reset(d, 0);
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    d->guest_slots[0].slot = slot;
Justin M. Forbes a81953
+    qxl_add_memslot(d, 0, devmem);
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    d->guest_primary.surface = surface;
Justin M. Forbes a81953
+    qxl_create_guest_primary(d, 0);
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    d->mode = QXL_MODE_COMPAT;
Justin M. Forbes a81953
+    d->cmdflags = QXL_COMMAND_FLAG_COMPAT;
Justin M. Forbes a81953
+    d->shadow_rom.mode = cpu_to_le32(modenr);
Justin M. Forbes a81953
+    d->rom->mode = cpu_to_le32(modenr);
Justin M. Forbes a81953
+    qxl_rom_set_dirty(d);
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void ioport_write(void *opaque, uint32_t addr, uint32_t val)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    PCIQXLDevice *d = opaque;
Justin M. Forbes a81953
+    uint32_t io_port = addr - d->io_base;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    switch (io_port) {
Justin M. Forbes a81953
+    case QXL_IO_RESET:
Justin M. Forbes a81953
+    case QXL_IO_SET_MODE:
Justin M. Forbes a81953
+    case QXL_IO_MEMSLOT_ADD:
Justin M. Forbes a81953
+    case QXL_IO_MEMSLOT_DEL:
Justin M. Forbes a81953
+    case QXL_IO_CREATE_PRIMARY:
Justin M. Forbes a81953
+        break;
Justin M. Forbes a81953
+    default:
Justin M. Forbes a81953
+        if (d->mode == QXL_MODE_NATIVE || d->mode == QXL_MODE_COMPAT)
Justin M. Forbes a81953
+            break;
Justin M. Forbes a81953
+        dprintf(d, 1, "%s: unexpected port 0x%x in vga mode\n", __FUNCTION__, io_port);
Justin M. Forbes a81953
+        return;
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    switch (io_port) {
Justin M. Forbes a81953
+    case QXL_IO_UPDATE_AREA:
Justin M. Forbes a81953
+    {
Justin M. Forbes a81953
+        QXLRect update = d->ram->update_area;
Justin M. Forbes a81953
+        d->ssd.worker->update_area(d->ssd.worker, d->ram->update_surface,
Justin M. Forbes a81953
+                                   &update, NULL, 0, 0);
Justin M. Forbes a81953
+        break;
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+    case QXL_IO_NOTIFY_CMD:
Justin M. Forbes a81953
+        d->ssd.worker->wakeup(d->ssd.worker);
Justin M. Forbes a81953
+        break;
Justin M. Forbes a81953
+    case QXL_IO_NOTIFY_CURSOR:
Justin M. Forbes a81953
+        d->ssd.worker->wakeup(d->ssd.worker);
Justin M. Forbes a81953
+        break;
Justin M. Forbes a81953
+    case QXL_IO_UPDATE_IRQ:
Justin M. Forbes a81953
+        qxl_set_irq(d);
Justin M. Forbes a81953
+        break;
Justin M. Forbes a81953
+    case QXL_IO_NOTIFY_OOM:
Justin M. Forbes a81953
+        if (!SPICE_RING_IS_EMPTY(&d->ram->release_ring)) {
Justin M. Forbes a81953
+            break;
Justin M. Forbes a81953
+        }
Justin M. Forbes a81953
+        pthread_yield();
Justin M. Forbes a81953
+        if (!SPICE_RING_IS_EMPTY(&d->ram->release_ring)) {
Justin M. Forbes a81953
+            break;
Justin M. Forbes a81953
+        }
Justin M. Forbes a81953
+        d->ssd.worker->oom(d->ssd.worker);
Justin M. Forbes a81953
+        break;
Justin M. Forbes a81953
+    case QXL_IO_SET_MODE:
Justin M. Forbes a81953
+        dprintf(d, 1, "QXL_SET_MODE %d\n", val);
Justin M. Forbes a81953
+        qxl_set_mode(d, val);
Justin M. Forbes a81953
+        break;
Justin M. Forbes a81953
+    case QXL_IO_LOG:
Justin M. Forbes a81953
+        dprintf(d, 1, "log %s", d->ram->log_buf);
Justin M. Forbes a81953
+        break;
Justin M. Forbes a81953
+    case QXL_IO_RESET:
Justin M. Forbes a81953
+        dprintf(d, 1, "QXL_IO_RESET\n");
Justin M. Forbes a81953
+        qxl_hard_reset(d, 0);
Justin M. Forbes a81953
+        break;
Justin M. Forbes a81953
+    case QXL_IO_MEMSLOT_ADD:
Justin M. Forbes a81953
+        PANIC_ON(val >= NUM_MEMSLOTS);
Justin M. Forbes a81953
+        PANIC_ON(d->guest_slots[val].active);
Justin M. Forbes a81953
+        d->guest_slots[val].slot = d->ram->mem_slot;
Justin M. Forbes a81953
+        qxl_add_memslot(d, val, 0);
Justin M. Forbes a81953
+        break;
Justin M. Forbes a81953
+    case QXL_IO_MEMSLOT_DEL:
Justin M. Forbes a81953
+        qxl_del_memslot(d, val);
Justin M. Forbes a81953
+        break;
Justin M. Forbes a81953
+    case QXL_IO_CREATE_PRIMARY:
Justin M. Forbes a81953
+        PANIC_ON(val != 0);
Justin M. Forbes a81953
+        dprintf(d, 1, "QXL_IO_CREATE_PRIMARY\n");
Justin M. Forbes a81953
+        d->guest_primary.surface = d->ram->create_surface;
Justin M. Forbes a81953
+        qxl_create_guest_primary(d, 0);
Justin M. Forbes a81953
+        break;
Justin M. Forbes a81953
+    case QXL_IO_DESTROY_PRIMARY:
Justin M. Forbes a81953
+        PANIC_ON(val != 0);
Justin M. Forbes a81953
+        dprintf(d, 1, "QXL_IO_DESTROY_PRIMARY\n");
Justin M. Forbes a81953
+        qxl_destroy_primary(d);
Justin M. Forbes a81953
+        break;
Justin M. Forbes a81953
+    case QXL_IO_DESTROY_SURFACE_WAIT:
Justin M. Forbes a81953
+        d->ssd.worker->destroy_surface_wait(d->ssd.worker, val);
Justin M. Forbes a81953
+        break;
Justin M. Forbes a81953
+    default:
Justin M. Forbes a81953
+        fprintf(stderr, "%s: ioport=0x%x, abort()\n", __FUNCTION__, io_port);
Justin M. Forbes a81953
+        abort();
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static uint32_t ioport_read(void *opaque, uint32_t addr)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    PCIQXLDevice *d = opaque;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    dprintf(d, 1, "%s: unexpected\n", __FUNCTION__);
Justin M. Forbes a81953
+    return 0xff;
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void qxl_map(PCIDevice *pci, int region_num,
Justin M. Forbes a81953
+                    pcibus_t addr, pcibus_t size, int type)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    static const char *names[] = {
Justin M. Forbes a81953
+        [ QXL_IO_RANGE_INDEX ]   = "ioports",
Justin M. Forbes a81953
+        [ QXL_RAM_RANGE_INDEX ]  = "devram",
Justin M. Forbes a81953
+        [ QXL_ROM_RANGE_INDEX ]  = "rom",
Justin M. Forbes a81953
+        [ QXL_VRAM_RANGE_INDEX ] = "vram",
Justin M. Forbes a81953
+    };
Justin M. Forbes a81953
+    PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, pci);
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    dprintf(qxl, 1, "%s: bar %d [%s] addr 0x%lx size 0x%lx\n", __FUNCTION__,
Justin M. Forbes a81953
+            region_num, names[region_num], addr, size);
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    switch (region_num) {
Justin M. Forbes a81953
+    case QXL_IO_RANGE_INDEX:
Justin M. Forbes a81953
+        register_ioport_write(addr, size, 1, ioport_write, pci);
Justin M. Forbes a81953
+        register_ioport_read(addr, size, 1, ioport_read, pci);
Justin M. Forbes a81953
+        qxl->io_base = addr;
Justin M. Forbes a81953
+        break;
Justin M. Forbes a81953
+    case QXL_RAM_RANGE_INDEX:
Justin M. Forbes a81953
+        cpu_register_physical_memory(addr, size, qxl->vga.vram_offset | IO_MEM_RAM);
Justin M. Forbes a81953
+        qxl->vga.map_addr = addr;
Justin M. Forbes a81953
+        qxl->vga.map_end = addr + size;
Justin M. Forbes a81953
+        if (qxl->id == 0) {
Justin M. Forbes a81953
+            vga_dirty_log_start(&qxl->vga);
Justin M. Forbes a81953
+        }
Justin M. Forbes a81953
+        break;
Justin M. Forbes a81953
+    case QXL_ROM_RANGE_INDEX:
Justin M. Forbes a81953
+        cpu_register_physical_memory(addr, size, qxl->rom_offset | IO_MEM_ROM);
Justin M. Forbes a81953
+        break;
Justin M. Forbes a81953
+    case QXL_VRAM_RANGE_INDEX:
Justin M. Forbes a81953
+        cpu_register_physical_memory(addr, size, qxl->vram_offset | IO_MEM_RAM);
Justin M. Forbes a81953
+        break;
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void pipe_read(void *opaque)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    PCIQXLDevice *d = opaque;
Justin M. Forbes a81953
+    char dummy;
Justin M. Forbes a81953
+    int len;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    do {
Justin M. Forbes a81953
+        len = read(d->pipe[0], &dummy, sizeof(dummy));
Justin M. Forbes a81953
+    } while (len == sizeof(dummy));
Justin M. Forbes a81953
+    qxl_set_irq(d);
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void qxl_send_events(PCIQXLDevice *d, uint32_t events)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    uint32_t old_pending;
Justin M. Forbes a81953
+    uint32_t le_events = cpu_to_le32(events);
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    assert(d->ssd.running);
Justin M. Forbes a81953
+    old_pending = __sync_fetch_and_or(&d->ram->int_pending, le_events);
Justin M. Forbes a81953
+    if ((old_pending & le_events) == le_events) {
Justin M. Forbes a81953
+        return;
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+    if (pthread_self() == d->main) {
Justin M. Forbes a81953
+        qxl_set_irq(d);
Justin M. Forbes a81953
+    } else {
Justin M. Forbes a81953
+        if (write(d->pipe[1], d, 1) != 1) {
Justin M. Forbes a81953
+            dprintf(d, 1, "%s: write to pipe failed\n", __FUNCTION__);
Justin M. Forbes a81953
+        }
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void init_pipe_signaling(PCIQXLDevice *d)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+   if (pipe(d->pipe) < 0) {
Justin M. Forbes a81953
+       dprintf(d, 1, "%s: pipe creation failed\n", __FUNCTION__);
Justin M. Forbes a81953
+       return;
Justin M. Forbes a81953
+   }
Justin M. Forbes a81953
+#ifdef CONFIG_IOTHREAD
Justin M. Forbes a81953
+   fcntl(d->pipe[0], F_SETFL, O_NONBLOCK);
Justin M. Forbes a81953
+#else
Justin M. Forbes a81953
+   fcntl(d->pipe[0], F_SETFL, O_NONBLOCK /* | O_ASYNC */);
Justin M. Forbes a81953
+#endif
Justin M. Forbes a81953
+   fcntl(d->pipe[1], F_SETFL, O_NONBLOCK);
Justin M. Forbes a81953
+   fcntl(d->pipe[0], F_SETOWN, getpid());
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+   d->main = pthread_self();
Justin M. Forbes a81953
+   qemu_set_fd_handler(d->pipe[0], pipe_read, NULL, d);
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+/* graphics console */
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void qxl_hw_update(void *opaque)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    PCIQXLDevice *qxl = opaque;
Justin M. Forbes a81953
+    VGACommonState *vga = &qxl->vga;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    switch (qxl->mode) {
Justin M. Forbes a81953
+    case QXL_MODE_VGA:
Justin M. Forbes a81953
+        vga->update(vga);
Justin M. Forbes a81953
+        break;
Justin M. Forbes a81953
+    case QXL_MODE_NATIVE:
Justin M. Forbes a81953
+        qxl_render_update(qxl);
Justin M. Forbes a81953
+        break;
Justin M. Forbes a81953
+    default:
Justin M. Forbes a81953
+        break;
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void qxl_hw_invalidate(void *opaque)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    PCIQXLDevice *qxl = opaque;
Justin M. Forbes a81953
+    VGACommonState *vga = &qxl->vga;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    vga->invalidate(vga);
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void qxl_hw_screen_dump(void *opaque, const char *filename)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    PCIQXLDevice *qxl = opaque;
Justin M. Forbes a81953
+    VGACommonState *vga = &qxl->vga;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    if (qxl->mode == QXL_MODE_VGA) {
Justin M. Forbes a81953
+        vga->screen_dump(vga, filename);
Justin M. Forbes a81953
+        return;
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void qxl_hw_text_update(void *opaque, console_ch_t *chardata)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    PCIQXLDevice *qxl = opaque;
Justin M. Forbes a81953
+    VGACommonState *vga = &qxl->vga;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    if (qxl->mode == QXL_MODE_VGA) {
Justin M. Forbes a81953
+        vga->text_update(vga, chardata);
Justin M. Forbes a81953
+        return;
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void qxl_vm_change_state_handler(void *opaque, int running, int reason)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    PCIQXLDevice *qxl = opaque;
Justin M. Forbes a81953
+    qemu_spice_vm_change_state_handler(&qxl->ssd, running, reason);
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+/* display change listener */
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void display_update(struct DisplayState *ds, int x, int y, int w, int h)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    if (qxl0->mode == QXL_MODE_VGA) {
Justin M. Forbes a81953
+        qemu_spice_display_update(&qxl0->ssd, x, y, w, h);
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void display_resize(struct DisplayState *ds)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    if (qxl0->mode == QXL_MODE_VGA) {
Justin M. Forbes a81953
+        qemu_spice_display_resize(&qxl0->ssd);
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void display_refresh(struct DisplayState *ds)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    if (qxl0->mode == QXL_MODE_VGA) {
Justin M. Forbes a81953
+        qemu_spice_display_refresh(&qxl0->ssd);
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static DisplayChangeListener display_listener = {
Justin M. Forbes a81953
+    .dpy_update  = display_update,
Justin M. Forbes a81953
+    .dpy_resize  = display_resize,
Justin M. Forbes a81953
+    .dpy_refresh = display_refresh,
Justin M. Forbes a81953
+};
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static int qxl_init(PCIDevice *dev)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, dev);
Justin M. Forbes a81953
+    VGACommonState *vga = &qxl->vga;
Justin M. Forbes a81953
+    uint8_t* config = qxl->pci.config;
Justin M. Forbes a81953
+    ram_addr_t ram_size = msb_mask(qxl->vga.vram_size * 2 - 1);
Justin M. Forbes a81953
+    uint32_t pci_device_id;
Justin M. Forbes a81953
+    uint32_t pci_device_rev;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    if (device_id == 0 && dev->qdev.hotplugged) {
Justin M. Forbes a81953
+        device_id++;
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    qxl->id = device_id;
Justin M. Forbes a81953
+    qxl->mode = QXL_MODE_UNDEFINED;
Justin M. Forbes a81953
+    qxl->generation = 1;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    switch (qxl->revision) {
Justin M. Forbes a81953
+    case 1: /* qxl-1 */
Justin M. Forbes a81953
+        pci_device_id  = 0x0100;
Justin M. Forbes a81953
+        pci_device_rev = 1;
Justin M. Forbes a81953
+        break;
Justin M. Forbes a81953
+    case 2: /* qxl-2 */
Justin M. Forbes a81953
+        pci_device_id  = 0x0100;
Justin M. Forbes a81953
+        pci_device_rev = 2;
Justin M. Forbes a81953
+        break;
Justin M. Forbes a81953
+    default: /* unstable */
Justin M. Forbes a81953
+        pci_device_id  = 0x01ff;
Justin M. Forbes a81953
+        pci_device_rev = 1;
Justin M. Forbes a81953
+        break;
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    if (!qxl->id) {
Justin M. Forbes a81953
+        if (ram_size < 32 * 1024 * 1024)
Justin M. Forbes a81953
+            ram_size = 32 * 1024 * 1024;
Justin M. Forbes a81953
+        vga_common_init(vga, ram_size);
Justin M. Forbes a81953
+        vga_init(vga);
Justin M. Forbes a81953
+        register_ioport_write(0x3c0, 16, 1, qxl_vga_ioport_write, vga);
Justin M. Forbes a81953
+        register_ioport_write(0x3b4,  2, 1, qxl_vga_ioport_write, vga);
Justin M. Forbes a81953
+        register_ioport_write(0x3d4,  2, 1, qxl_vga_ioport_write, vga);
Justin M. Forbes a81953
+        register_ioport_write(0x3ba,  1, 1, qxl_vga_ioport_write, vga);
Justin M. Forbes a81953
+        register_ioport_write(0x3da,  1, 1, qxl_vga_ioport_write, vga);
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+        vga->ds = graphic_console_init(qxl_hw_update, qxl_hw_invalidate,
Justin M. Forbes a81953
+                                       qxl_hw_screen_dump, qxl_hw_text_update, qxl);
Justin M. Forbes a81953
+        qxl->ssd.ds = vga->ds;
Justin M. Forbes a81953
+        qxl->ssd.bufsize = (16 * 1024 * 1024);
Justin M. Forbes a81953
+        qxl->ssd.buf = qemu_malloc(qxl->ssd.bufsize);
Justin M. Forbes a81953
+        pthread_mutex_init(&qxl->ssd.lock, NULL);
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+        qxl0 = qxl;
Justin M. Forbes a81953
+        register_displaychangelistener(vga->ds, &display_listener);
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+        if (qxl->pci.romfile == NULL) {
Justin M. Forbes a81953
+            if (pci_device_id == 0x01ff) {
Justin M. Forbes a81953
+                qxl->pci.romfile = qemu_strdup("vgabios-qxldev.bin");
Justin M. Forbes a81953
+            } else {
Justin M. Forbes a81953
+                qxl->pci.romfile = qemu_strdup("vgabios-qxl.bin");
Justin M. Forbes a81953
+            }
Justin M. Forbes a81953
+        }
Justin M. Forbes a81953
+        pci_config_set_class(config, PCI_CLASS_DISPLAY_VGA);
Justin M. Forbes a81953
+    } else {
Justin M. Forbes a81953
+        if (ram_size < 16 * 1024 * 1024)
Justin M. Forbes a81953
+            ram_size = 16 * 1024 * 1024;
Justin M. Forbes a81953
+        qxl->vga.vram_size = ram_size;
Justin M. Forbes a81953
+        qxl->vga.vram_offset = qemu_ram_alloc(&qxl->pci.qdev, "bar0", qxl->vga.vram_size);
Justin M. Forbes a81953
+        qxl->vga.vram_ptr = qemu_get_ram_ptr(qxl->vga.vram_offset);
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+        pci_config_set_class(config, PCI_CLASS_DISPLAY_OTHER);
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    pci_config_set_vendor_id(config, REDHAT_PCI_VENDOR_ID);
Justin M. Forbes a81953
+    pci_config_set_device_id(config, pci_device_id);
Justin M. Forbes a81953
+    pci_set_byte(&config[PCI_REVISION_ID], pci_device_rev);
Justin M. Forbes a81953
+    pci_set_byte(&config[PCI_INTERRUPT_PIN], 1);
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    qxl->rom_size = qxl_rom_size();
Justin M. Forbes a81953
+    qxl->rom_offset = qemu_ram_alloc(&qxl->pci.qdev, "bar2", qxl->rom_size);
Justin M. Forbes a81953
+    init_qxl_rom(qxl);
Justin M. Forbes a81953
+    init_qxl_ram(qxl);
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    if (qxl->vram_size < 16 * 1024 * 1024)
Justin M. Forbes a81953
+        qxl->vram_size = 16 * 1024 * 1024;
Justin M. Forbes a81953
+    qxl->vram_size = msb_mask(qxl->vram_size * 2 - 1);
Justin M. Forbes a81953
+    qxl->vram_offset = qemu_ram_alloc(&qxl->pci.qdev, "bar1", qxl->vram_size);
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    pci_register_bar(&qxl->pci, QXL_IO_RANGE_INDEX,
Justin M. Forbes a81953
+                     msb_mask(QXL_IO_RANGE_SIZE * 2 - 1),
Justin M. Forbes a81953
+                     PCI_BASE_ADDRESS_SPACE_IO, qxl_map);
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    pci_register_bar(&qxl->pci, QXL_ROM_RANGE_INDEX,
Justin M. Forbes a81953
+                     qxl->rom_size, PCI_BASE_ADDRESS_SPACE_MEMORY,
Justin M. Forbes a81953
+                     qxl_map);
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    pci_register_bar(&qxl->pci, QXL_RAM_RANGE_INDEX,
Justin M. Forbes a81953
+                     qxl->vga.vram_size, PCI_BASE_ADDRESS_SPACE_MEMORY,
Justin M. Forbes a81953
+                     qxl_map);
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    pci_register_bar(&qxl->pci, QXL_VRAM_RANGE_INDEX, qxl->vram_size,
Justin M. Forbes a81953
+                     PCI_BASE_ADDRESS_SPACE_MEMORY, qxl_map);
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    qxl->ssd.qxl.base.sif = &qxl_interface.base;
Justin M. Forbes a81953
+    qxl->ssd.qxl.id = qxl->id;
Justin M. Forbes a81953
+    spice_server_add_interface(spice_server, &qxl->ssd.qxl.base);
Justin M. Forbes a81953
+    qemu_add_vm_change_state_handler(qxl_vm_change_state_handler, qxl);
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    init_pipe_signaling(qxl);
Justin M. Forbes a81953
+    qxl_reset_state(qxl);
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    device_id++;
Justin M. Forbes a81953
+    return 0;
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void qxl_pre_save(void *opaque)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    PCIQXLDevice* d = opaque;
Justin M. Forbes a81953
+    uint8_t *ram_start = d->vga.vram_ptr;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    dprintf(d, 1, "%s:\n", __FUNCTION__);
Justin M. Forbes a81953
+#if 1 /* wanna zap this */
Justin M. Forbes a81953
+    if (d->last_release == NULL) {
Justin M. Forbes a81953
+        d->last_release_offset = 0;
Justin M. Forbes a81953
+    } else {
Justin M. Forbes a81953
+        d->last_release_offset = (uint8_t *)d->last_release - ram_start;
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+    assert(d->last_release_offset < d->vga.vram_size);
Justin M. Forbes a81953
+#endif
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static int qxl_pre_load(void *opaque)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    PCIQXLDevice* d = opaque;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    dprintf(d, 1, "%s: start\n", __FUNCTION__);
Justin M. Forbes a81953
+    qxl_hard_reset(d, 1);
Justin M. Forbes a81953
+    qxl_exit_vga_mode(d);
Justin M. Forbes a81953
+    dprintf(d, 1, "%s: done\n", __FUNCTION__);
Justin M. Forbes a81953
+    return 0;
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static int qxl_post_load(void *opaque, int version)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    PCIQXLDevice* d = opaque;
Justin M. Forbes a81953
+    uint8_t *ram_start = d->vga.vram_ptr;
Justin M. Forbes a81953
+    QXLCommandExt *cmds;
Justin M. Forbes a81953
+    int in, out, i, newmode;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    dprintf(d, 1, "%s: start\n", __FUNCTION__);
Justin M. Forbes a81953
+    newmode = d->mode;
Justin M. Forbes a81953
+    d->mode = QXL_MODE_UNDEFINED;
Justin M. Forbes a81953
+    switch (newmode) {
Justin M. Forbes a81953
+    case QXL_MODE_UNDEFINED:
Justin M. Forbes a81953
+        break;
Justin M. Forbes a81953
+    case QXL_MODE_VGA:
Justin M. Forbes a81953
+        qxl_enter_vga_mode(d);
Justin M. Forbes a81953
+        break;
Justin M. Forbes a81953
+    case QXL_MODE_NATIVE:
Justin M. Forbes a81953
+        for (i = 0; i < NUM_MEMSLOTS; i++) {
Justin M. Forbes a81953
+            if (!d->guest_slots[i].active)
Justin M. Forbes a81953
+                continue;
Justin M. Forbes a81953
+            qxl_add_memslot(d, i, 0);
Justin M. Forbes a81953
+        }
Justin M. Forbes a81953
+        qxl_create_guest_primary(d, 1);
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+        /* replay surface-create and cursor-set commands */
Justin M. Forbes a81953
+        cmds = qemu_mallocz(sizeof(QXLCommandExt) * (NUM_SURFACES + 1));
Justin M. Forbes a81953
+        for (in = 0, out = 0; in < NUM_SURFACES; in++) {
Justin M. Forbes a81953
+            if (d->guest_surfaces.cmds[in] == 0)
Justin M. Forbes a81953
+                continue;
Justin M. Forbes a81953
+            cmds[out].cmd.data = d->guest_surfaces.cmds[in];
Justin M. Forbes a81953
+            cmds[out].cmd.type = QXL_CMD_SURFACE;
Justin M. Forbes a81953
+            cmds[out].group_id = MEMSLOT_GROUP_GUEST;
Justin M. Forbes a81953
+            out++;
Justin M. Forbes a81953
+        }
Justin M. Forbes a81953
+        cmds[out].cmd.data = d->guest_cursor;
Justin M. Forbes a81953
+        cmds[out].cmd.type = QXL_CMD_CURSOR;
Justin M. Forbes a81953
+        cmds[out].group_id = MEMSLOT_GROUP_GUEST;
Justin M. Forbes a81953
+        out++;
Justin M. Forbes a81953
+        d->ssd.worker->loadvm_commands(d->ssd.worker, cmds, out);
Justin M. Forbes a81953
+        qemu_free(cmds);
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+        break;
Justin M. Forbes a81953
+    case QXL_MODE_COMPAT:
Justin M. Forbes a81953
+        qxl_set_mode(d, d->shadow_rom.mode);
Justin M. Forbes a81953
+        break;
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+    dprintf(d, 1, "%s: done\n", __FUNCTION__);
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+#if 1 /* wanna zap this */
Justin M. Forbes a81953
+    if (d->last_release_offset >= d->vga.vram_size) {
Justin M. Forbes a81953
+        dprintf(d, 1, "%s: invalid last_release_offset %u, ram_size %u\n",
Justin M. Forbes a81953
+                __FUNCTION__, d->last_release_offset, d->vga.vram_size);
Justin M. Forbes a81953
+        exit(-1);
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    if (d->last_release_offset == 0) {
Justin M. Forbes a81953
+        d->last_release = NULL;
Justin M. Forbes a81953
+    } else {
Justin M. Forbes a81953
+        d->last_release = (QXLReleaseInfo *)(ram_start + d->last_release_offset);
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+#endif
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    return 0;
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+#define QXL_VER 1
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static VMStateDescription qxl_memslot = {
Justin M. Forbes a81953
+    .name               = "qxl-memslot",
Justin M. Forbes a81953
+    .version_id         = QXL_VER,
Justin M. Forbes a81953
+    .minimum_version_id = QXL_VER,
Justin M. Forbes a81953
+    .fields = (VMStateField[]) {
Justin M. Forbes a81953
+        VMSTATE_UINT64(slot.mem_start, struct guest_slots),
Justin M. Forbes a81953
+        VMSTATE_UINT64(slot.mem_end,   struct guest_slots),
Justin M. Forbes a81953
+        VMSTATE_UINT32(active,         struct guest_slots),
Justin M. Forbes a81953
+        VMSTATE_END_OF_LIST()
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+};
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static VMStateDescription qxl_surface = {
Justin M. Forbes a81953
+    .name               = "qxl-surface",
Justin M. Forbes a81953
+    .version_id         = QXL_VER,
Justin M. Forbes a81953
+    .minimum_version_id = QXL_VER,
Justin M. Forbes a81953
+    .fields = (VMStateField[]) {
Justin M. Forbes a81953
+        VMSTATE_UINT32(width,      QXLSurfaceCreate),
Justin M. Forbes a81953
+        VMSTATE_UINT32(height,     QXLSurfaceCreate),
Justin M. Forbes a81953
+        VMSTATE_INT32(stride,      QXLSurfaceCreate),
Justin M. Forbes a81953
+        VMSTATE_UINT32(format,     QXLSurfaceCreate),
Justin M. Forbes a81953
+        VMSTATE_UINT32(position,   QXLSurfaceCreate),
Justin M. Forbes a81953
+        VMSTATE_UINT32(mouse_mode, QXLSurfaceCreate),
Justin M. Forbes a81953
+        VMSTATE_UINT32(flags,      QXLSurfaceCreate),
Justin M. Forbes a81953
+        VMSTATE_UINT32(type,       QXLSurfaceCreate),
Justin M. Forbes a81953
+        VMSTATE_UINT64(mem,        QXLSurfaceCreate),
Justin M. Forbes a81953
+        VMSTATE_END_OF_LIST()
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+};
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static VMStateDescription qxl_vmstate = {
Justin M. Forbes a81953
+    .name               = "qxl",
Justin M. Forbes a81953
+    .version_id         = QXL_VER,
Justin M. Forbes a81953
+    .minimum_version_id = QXL_VER,
Justin M. Forbes a81953
+    .pre_save           = qxl_pre_save,
Justin M. Forbes a81953
+    .pre_load           = qxl_pre_load,
Justin M. Forbes a81953
+    .post_load          = qxl_post_load,
Justin M. Forbes a81953
+    .fields = (VMStateField []) {
Justin M. Forbes a81953
+        VMSTATE_PCI_DEVICE(pci, PCIQXLDevice),
Justin M. Forbes a81953
+        VMSTATE_STRUCT(vga, PCIQXLDevice, QXL_VER, vmstate_vga_common, VGACommonState),
Justin M. Forbes a81953
+        VMSTATE_UINT32(shadow_rom.mode, PCIQXLDevice),
Justin M. Forbes a81953
+#if 1 /* wanna zap this */
Justin M. Forbes a81953
+        VMSTATE_UINT32(num_free_res, PCIQXLDevice),
Justin M. Forbes a81953
+        VMSTATE_UINT32(last_release_offset, PCIQXLDevice),
Justin M. Forbes a81953
+#endif
Justin M. Forbes a81953
+        VMSTATE_UINT32(mode, PCIQXLDevice),
Justin M. Forbes a81953
+        VMSTATE_UINT32(ssd.unique, PCIQXLDevice),
Justin M. Forbes a81953
+#if 1 /* new stuff */
Justin M. Forbes a81953
+        VMSTATE_STRUCT_ARRAY(guest_slots, PCIQXLDevice, NUM_MEMSLOTS, QXL_VER,
Justin M. Forbes a81953
+                             qxl_memslot, struct guest_slots),
Justin M. Forbes a81953
+        VMSTATE_STRUCT(guest_primary.surface, PCIQXLDevice, QXL_VER,
Justin M. Forbes a81953
+                       qxl_surface, QXLSurfaceCreate),
Justin M. Forbes a81953
+        VMSTATE_ARRAY(guest_surfaces.cmds, PCIQXLDevice, NUM_SURFACES, QXL_VER,
Justin M. Forbes a81953
+                      vmstate_info_uint64, uint64_t),
Justin M. Forbes a81953
+        VMSTATE_UINT64(guest_cursor, PCIQXLDevice),
Justin M. Forbes a81953
+#endif
Justin M. Forbes a81953
+        VMSTATE_END_OF_LIST()
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+};
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static PCIDeviceInfo qxl_info = {
Justin M. Forbes a81953
+    .qdev.name    = "qxl",
Justin M. Forbes a81953
+    .qdev.desc    = "Spice QXL GPU",
Justin M. Forbes a81953
+    .qdev.size    = sizeof(PCIQXLDevice),
Justin M. Forbes a81953
+    .qdev.reset   = qxl_reset_handler,
Justin M. Forbes a81953
+    .qdev.vmsd    = &qxl_vmstate,
Justin M. Forbes a81953
+    .init         = qxl_init,
Justin M. Forbes a81953
+    .config_write = qxl_write_config,
Justin M. Forbes a81953
+    .qdev.props = (Property[]) {
Justin M. Forbes a81953
+        DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size, 64 * 1024 * 1024),
Justin M. Forbes a81953
+        DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram_size, 64 * 1024 * 1024),
Justin M. Forbes a81953
+        DEFINE_PROP_UINT32("revision", PCIQXLDevice, revision, 3),
Justin M. Forbes a81953
+        DEFINE_PROP_UINT32("debug", PCIQXLDevice, debug, 0),
Justin M. Forbes a81953
+        DEFINE_PROP_UINT32("cmdlog", PCIQXLDevice, cmdlog, 0),
Justin M. Forbes a81953
+        DEFINE_PROP_END_OF_LIST(),
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+};
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void qxl_register(void)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    pci_qdev_register(&qxl_info);
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+device_init(qxl_register);
Justin M. Forbes a81953
diff --git a/hw/qxl.h b/hw/qxl.h
Justin M. Forbes a81953
new file mode 100644
Justin M. Forbes a81953
index 0000000..1216405
Justin M. Forbes a81953
--- /dev/null
Justin M. Forbes a81953
+++ b/hw/qxl.h
Justin M. Forbes a81953
@@ -0,0 +1,102 @@
Justin M. Forbes a81953
+#include "console.h"
Justin M. Forbes a81953
+#include "hw.h"
Justin M. Forbes a81953
+#include "pci.h"
Justin M. Forbes a81953
+#include "vga_int.h"
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+#include "qemu-spice.h"
Justin M. Forbes a81953
+#include "spice-display.h"
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+enum qxl_mode {
Justin M. Forbes a81953
+    QXL_MODE_UNDEFINED,
Justin M. Forbes a81953
+    QXL_MODE_VGA,
Justin M. Forbes a81953
+    QXL_MODE_COMPAT, /* spice 0.4.x */
Justin M. Forbes a81953
+    QXL_MODE_NATIVE,
Justin M. Forbes a81953
+};
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+typedef struct PCIQXLDevice {
Justin M. Forbes a81953
+    PCIDevice          pci;
Justin M. Forbes a81953
+    SimpleSpiceDisplay ssd;
Justin M. Forbes a81953
+    int                id;
Justin M. Forbes a81953
+    uint32_t           debug;
Justin M. Forbes a81953
+    uint32_t           cmdlog;
Justin M. Forbes a81953
+    enum qxl_mode      mode;
Justin M. Forbes a81953
+    uint32_t           cmdflags;
Justin M. Forbes a81953
+    int                generation;
Justin M. Forbes a81953
+    uint32_t           revision;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    struct guest_slots {
Justin M. Forbes a81953
+        QXLMemSlot     slot;
Justin M. Forbes a81953
+        void           *ptr;
Justin M. Forbes a81953
+        uint64_t       size;
Justin M. Forbes a81953
+        uint64_t       delta;
Justin M. Forbes a81953
+        uint32_t       active;
Justin M. Forbes a81953
+    } guest_slots[NUM_MEMSLOTS];
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    struct guest_primary {
Justin M. Forbes a81953
+        QXLSurfaceCreate surface;
Justin M. Forbes a81953
+        uint32_t       commands;
Justin M. Forbes a81953
+        uint32_t       resized;
Justin M. Forbes a81953
+        int32_t        stride;
Justin M. Forbes a81953
+        uint32_t       bits_pp;
Justin M. Forbes a81953
+        uint32_t       bytes_pp;
Justin M. Forbes a81953
+        uint8_t        *data, *flipped;
Justin M. Forbes a81953
+    } guest_primary;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    struct surfaces {
Justin M. Forbes a81953
+        QXLPHYSICAL    cmds[NUM_SURFACES];
Justin M. Forbes a81953
+        uint32_t       count;
Justin M. Forbes a81953
+        uint32_t       max;
Justin M. Forbes a81953
+    } guest_surfaces;
Justin M. Forbes a81953
+    QXLPHYSICAL        guest_cursor;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    /* thread signaling */
Justin M. Forbes a81953
+    pthread_t          main;
Justin M. Forbes a81953
+    int                pipe[2];
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    /* ram pci bar */
Justin M. Forbes a81953
+    QXLRam             *ram;
Justin M. Forbes a81953
+    VGACommonState     vga;
Justin M. Forbes a81953
+    uint32_t           num_free_res;
Justin M. Forbes a81953
+    QXLReleaseInfo     *last_release;
Justin M. Forbes a81953
+    uint32_t           last_release_offset;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    /* rom pci bar */
Justin M. Forbes a81953
+    QXLRom             shadow_rom;
Justin M. Forbes a81953
+    QXLRom             *rom;
Justin M. Forbes a81953
+    QXLModes           *modes;
Justin M. Forbes a81953
+    uint32_t           rom_size;
Justin M. Forbes a81953
+    uint64_t           rom_offset;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    /* vram pci bar */
Justin M. Forbes a81953
+    uint32_t           vram_size;
Justin M. Forbes a81953
+    uint64_t           vram_offset;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    /* io bar */
Justin M. Forbes a81953
+    uint32_t           io_base;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+} PCIQXLDevice;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+#define PANIC_ON(x) if ((x)) {                         \
Justin M. Forbes a81953
+    printf("%s: PANIC %s failed\n", __FUNCTION__, #x); \
Justin M. Forbes a81953
+    exit(-1);                                          \
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+#define dprintf(_qxl, _level, _fmt, ...)                                \
Justin M. Forbes a81953
+    do {                                                                \
Justin M. Forbes a81953
+        if (_qxl->debug >= _level) {                                    \
Justin M. Forbes a81953
+            fprintf(stderr, "qxl-%d: ", _qxl->id);                      \
Justin M. Forbes a81953
+            fprintf(stderr, _fmt, ## __VA_ARGS__);                      \
Justin M. Forbes a81953
+        }                                                               \
Justin M. Forbes a81953
+    } while (0)
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+/* qxl.c */
Justin M. Forbes a81953
+void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id);
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+/* qxl-logger.c */
Justin M. Forbes a81953
+void qxl_log_cmd_cursor(PCIQXLDevice *qxl, QXLCursorCmd *cmd, int group_id);
Justin M. Forbes a81953
+void qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext);
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+/* qxl-render.c */
Justin M. Forbes a81953
+void qxl_render_resize(PCIQXLDevice *qxl);
Justin M. Forbes a81953
+void qxl_render_update(PCIQXLDevice *qxl);
Justin M. Forbes a81953
+void qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext);
Justin M. Forbes a81953
diff --git a/hw/vga_int.h b/hw/vga_int.h
Justin M. Forbes a81953
index 70e0f19..4a82683 100644
Justin M. Forbes a81953
--- a/hw/vga_int.h
Justin M. Forbes a81953
+++ b/hw/vga_int.h
Justin M. Forbes a81953
@@ -106,7 +106,7 @@ typedef void (* vga_update_retrace_info_fn)(struct VGACommonState *s);
Justin M. Forbes a81953
 typedef struct VGACommonState {
Justin M. Forbes a81953
     uint8_t *vram_ptr;
Justin M. Forbes a81953
     ram_addr_t vram_offset;
Justin M. Forbes a81953
-    unsigned int vram_size;
Justin M. Forbes a81953
+    uint32_t vram_size;
Justin M. Forbes a81953
     uint32_t lfb_addr;
Justin M. Forbes a81953
     uint32_t lfb_end;
Justin M. Forbes a81953
     uint32_t map_addr;
Justin M. Forbes a81953
diff --git a/sysemu.h b/sysemu.h
Justin M. Forbes a81953
index bf1d68a..ea3634d 100644
Justin M. Forbes a81953
--- a/sysemu.h
Justin M. Forbes a81953
+++ b/sysemu.h
Justin M. Forbes a81953
@@ -103,7 +103,7 @@ extern int autostart;
Justin M. Forbes a81953
 extern int bios_size;
Justin M. Forbes a81953
Justin M. Forbes a81953
 typedef enum {
Justin M. Forbes a81953
-    VGA_NONE, VGA_STD, VGA_CIRRUS, VGA_VMWARE, VGA_XENFB
Justin M. Forbes a81953
+    VGA_NONE, VGA_STD, VGA_CIRRUS, VGA_VMWARE, VGA_XENFB, VGA_QXL,
Justin M. Forbes a81953
 } VGAInterfaceType;
Justin M. Forbes a81953
Justin M. Forbes a81953
 extern int vga_interface_type;
Justin M. Forbes a81953
@@ -111,6 +111,7 @@ extern int vga_interface_type;
Justin M. Forbes a81953
 #define std_vga_enabled (vga_interface_type == VGA_STD)
Justin M. Forbes a81953
 #define xenfb_enabled (vga_interface_type == VGA_XENFB)
Justin M. Forbes a81953
 #define vmsvga_enabled (vga_interface_type == VGA_VMWARE)
Justin M. Forbes a81953
+#define qxl_enabled (vga_interface_type == VGA_QXL)
Justin M. Forbes a81953
Justin M. Forbes a81953
 extern int graphic_width;
Justin M. Forbes a81953
 extern int graphic_height;
Justin M. Forbes a81953
diff --git a/vl.c b/vl.c
Justin M. Forbes a81953
index 2ccebc8..eb630bd 100644
Justin M. Forbes a81953
--- a/vl.c
Justin M. Forbes a81953
+++ b/vl.c
Justin M. Forbes a81953
@@ -1459,6 +1459,8 @@ static void select_vgahw (const char *p)
Justin M. Forbes a81953
         vga_interface_type = VGA_VMWARE;
Justin M. Forbes a81953
     } else if (strstart(p, "xenfb", &opts)) {
Justin M. Forbes a81953
         vga_interface_type = VGA_XENFB;
Justin M. Forbes a81953
+    } else if (strstart(p, "qxl", &opts)) {
Justin M. Forbes a81953
+        vga_interface_type = VGA_QXL;
Justin M. Forbes a81953
     } else if (!strstart(p, "none", &opts)) {
Justin M. Forbes a81953
     invalid_vga:
Justin M. Forbes a81953
         fprintf(stderr, "Unknown vga type: %s\n", p);
Justin M. Forbes a81953
@@ -3034,7 +3036,7 @@ int main(int argc, char **argv, char **envp)
Justin M. Forbes a81953
         break;
Justin M. Forbes a81953
     }
Justin M. Forbes a81953
 #ifdef CONFIG_SPICE
Justin M. Forbes a81953
-    if (using_spice) {
Justin M. Forbes a81953
+    if (using_spice && !qxl_enabled) {
Justin M. Forbes a81953
         qemu_spice_display_init(ds);
Justin M. Forbes a81953
     }
Justin M. Forbes a81953
 #endif
Justin M. Forbes a81953
-- 
Justin M. Forbes a81953
1.7.2.3
Justin M. Forbes a81953