All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [RfC PATCH 00/15] virtio-gpu:
@ 2015-02-23 10:23 Gerd Hoffmann
  2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 01/15] virtio-pci: add flags to enable/disable legacy/modern Gerd Hoffmann
                   ` (15 more replies)
  0 siblings, 16 replies; 44+ messages in thread
From: Gerd Hoffmann @ 2015-02-23 10:23 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

  Hi,

After a loooong break, here is the next version of virtio-gpu patches.
It is the first batch, with the 2d bits, virgl (3d/opengl) support will
follow later on.

The dust of the virtio-1.0 merge has mostly settled, even though not
all virtio-1.0 bits are upstream yet (main reason why this is RfC).  My
plan is to get virtio-gpu merged upstream as soon as all dependencies
are in.

This series applies on top of mst's virtio-1.0 branch.

Patches 1-4 are virtio-pci patches which have been posted separately
already, included here because the virtio-gpu patches depend on them.

Patches 5-14 are virtio-gpu and virtio-vga patches.  Patches 8+10 with
the virtio-1.0 changes depend on patches 1-4.  I've kept them separate
for now, to simplify review and also to make adaptions easier in case
patches 1-4 are changed during review.  Patch series is not fully
bisectable because of this.  For the non-RfC patch series they will of
course be squashed in.

Patch 15 is a dirty hack to simplify testing with libvirt, this will
be dropped for the merge, we'll need proper libvirt support instead.

If you wanna play with this, here are host + guest git trees for your
convinience:
    git://git.kraxel.org/qemu tags/virtio-gpu-rfc-2015-02-23
    git://git.kraxel.org/linux virtio-gpu

Usage:
   qemu-system-x86_64 -vga virtio [ ... ]
   qemu-system-x86_64 -device virtio-vga [ ... ]
   qemu-system-ppc64 -M pseries -device virtio-gpu-pci [ ... ]
   qemu-system-arm -M virt -device virtio-gpu-device [ ... ]

Gerd Hoffmann (15):
  virtio-pci: add flags to enable/disable legacy/modern
  virtio-pci: make QEMU_VIRTIO_PCI_QUEUE_MEM_MULT smaller
  virtio-pci: make pci bars configurable
  virtio-pci: make modern bar 64bit prefetchable
  virtio-gpu/2d: add hardware spec include file
  virtio-gpu/2d: add virtio gpu core code
  virtio-gpu-pci: add virtio pci support
  virtio-gpu-pci: virtio-1.0 adaptions [fixup]
  virtio-vga: add virtio gpu device with vga compatibility
  virtio-vga: virtio-1.0 adaptions [fixup]
  virtio-vga: add '-vga virtio' support
  virtio-vga: add vgabios configuration
  virtio-vga: add vgabios binary
  virtio-gpu: add to display-vga test
  [hack] virtio-gpu: maskerade as -device VGA

 Makefile                           |   2 +-
 default-configs/x86_64-softmmu.mak |   1 +
 hw/display/Makefile.objs           |   4 +
 hw/display/vga-pci.c               |   2 +-
 hw/display/virtio-gpu-pci.c        |  68 +++
 hw/display/virtio-gpu.c            | 903 +++++++++++++++++++++++++++++++++++++
 hw/display/virtio-vga.c            | 158 +++++++
 hw/pci/pci.c                       |   2 +
 hw/virtio/virtio-pci.c             |  81 +++-
 hw/virtio/virtio-pci.h             |  23 +
 include/hw/pci/pci.h               |   1 +
 include/hw/virtio/virtgpu_hw.h     | 203 +++++++++
 include/hw/virtio/virtio-gpu.h     | 147 ++++++
 include/sysemu/sysemu.h            |   2 +-
 pc-bios/vgabios-virtio.bin         | Bin 0 -> 37376 bytes
 roms/Makefile                      |   2 +-
 roms/config.vga-virtio             |   6 +
 tests/Makefile                     |   3 +
 tests/display-vga-test.c           |  18 +
 trace-events                       |  14 +
 vl.c                               |  13 +
 21 files changed, 1630 insertions(+), 23 deletions(-)
 create mode 100644 hw/display/virtio-gpu-pci.c
 create mode 100644 hw/display/virtio-gpu.c
 create mode 100644 hw/display/virtio-vga.c
 create mode 100644 include/hw/virtio/virtgpu_hw.h
 create mode 100644 include/hw/virtio/virtio-gpu.h
 create mode 100644 pc-bios/vgabios-virtio.bin
 create mode 100644 roms/config.vga-virtio

-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [Qemu-devel] [RfC PATCH 01/15] virtio-pci: add flags to enable/disable legacy/modern
  2015-02-23 10:23 [Qemu-devel] [RfC PATCH 00/15] virtio-gpu: Gerd Hoffmann
@ 2015-02-23 10:23 ` Gerd Hoffmann
  2015-02-26 16:41   ` Max Reitz
  2015-03-02 12:34   ` Michael S. Tsirkin
  2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 02/15] virtio-pci: make QEMU_VIRTIO_PCI_QUEUE_MEM_MULT smaller Gerd Hoffmann
                   ` (14 subsequent siblings)
  15 siblings, 2 replies; 44+ messages in thread
From: Gerd Hoffmann @ 2015-02-23 10:23 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann, Anthony Liguori, Michael S. Tsirkin

Add VIRTIO_PCI_FLAG_DISABLE_LEGACY and VIRTIO_PCI_FLAG_DISABLE_MODERN
for VirtIOPCIProxy->flags.  Also add properties for them.  They can be
used to disable modern (virtio 1.0) or legacy (virtio 0.9) modes.  By
default both are advertized and the guest driver can choose.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/virtio/virtio-pci.c | 46 +++++++++++++++++++++++++++++++++-------------
 hw/virtio/virtio-pci.h |  6 ++++++
 2 files changed, 39 insertions(+), 13 deletions(-)

diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index 4c9a0b8..6c0c650 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -1233,6 +1233,8 @@ static void virtio_pci_device_plugged(DeviceState *d)
 {
     VirtIOPCIProxy *proxy = VIRTIO_PCI(d);
     VirtioBusState *bus = &proxy->bus;
+    bool legacy = !(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_LEGACY);
+    bool modern = !(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_MODERN);
     uint8_t *config;
     uint32_t size;
 
@@ -1240,13 +1242,24 @@ static void virtio_pci_device_plugged(DeviceState *d)
     if (proxy->class_code) {
         pci_config_set_class(config, proxy->class_code);
     }
-    pci_set_word(config + PCI_SUBSYSTEM_VENDOR_ID,
-                 pci_get_word(config + PCI_VENDOR_ID));
-    pci_set_word(config + PCI_SUBSYSTEM_ID, virtio_bus_get_vdev_id(bus));
+
+    if (legacy) {
+        /* legacy and transitional */
+        pci_set_word(config + PCI_SUBSYSTEM_VENDOR_ID,
+                     pci_get_word(config + PCI_VENDOR_ID));
+        pci_set_word(config + PCI_SUBSYSTEM_ID, virtio_bus_get_vdev_id(bus));
+    } else {
+        /* pure virtio-1.0 */
+        pci_set_word(config + PCI_VENDOR_ID,
+                     PCI_VENDOR_ID_REDHAT_QUMRANET);
+        pci_set_word(config + PCI_DEVICE_ID,
+                     0x1040 + virtio_bus_get_vdev_id(bus));
+        pci_config_set_revision(config, 1);
+    }
     config[PCI_INTERRUPT_PIN] = 1;
 
 
-    if (1) { /* TODO: Make this optional, dependent on virtio 1.0 */
+    if (modern) {
         struct virtio_pci_cap common = {
             .cfg_type = VIRTIO_PCI_CAP_COMMON_CFG,
             .cap_len = sizeof common,
@@ -1359,17 +1372,20 @@ static void virtio_pci_device_plugged(DeviceState *d)
 
     proxy->pci_dev.config_write = virtio_write_config;
 
-    size = VIRTIO_PCI_REGION_SIZE(&proxy->pci_dev)
-         + virtio_bus_get_vdev_config_len(bus);
-    if (size & (size - 1)) {
-        size = 1 << qemu_fls(size);
-    }
+    if (legacy) {
+        size = VIRTIO_PCI_REGION_SIZE(&proxy->pci_dev)
+            + virtio_bus_get_vdev_config_len(bus);
+        if (size & (size - 1)) {
+            size = 1 << qemu_fls(size);
+        }
 
-    memory_region_init_io(&proxy->bar, OBJECT(proxy), &virtio_pci_config_ops,
-                          proxy, "virtio-pci", size);
+        memory_region_init_io(&proxy->bar, OBJECT(proxy),
+                              &virtio_pci_config_ops,
+                              proxy, "virtio-pci", size);
 
-    pci_register_bar(&proxy->pci_dev, 0, PCI_BASE_ADDRESS_SPACE_IO,
-                     &proxy->bar);
+        pci_register_bar(&proxy->pci_dev, 0, PCI_BASE_ADDRESS_SPACE_IO,
+                         &proxy->bar);
+    }
 
     if (!kvm_has_many_ioeventfds()) {
         proxy->flags &= ~VIRTIO_PCI_FLAG_USE_IOEVENTFD;
@@ -1416,6 +1432,10 @@ static void virtio_pci_reset(DeviceState *qdev)
 static Property virtio_pci_properties[] = {
     DEFINE_PROP_BIT("virtio-pci-bus-master-bug-migration", VirtIOPCIProxy, flags,
                     VIRTIO_PCI_FLAG_BUS_MASTER_BUG_MIGRATION_BIT, false),
+    DEFINE_PROP_BIT("disable-legacy", VirtIOPCIProxy, flags,
+                    VIRTIO_PCI_FLAG_DISABLE_LEGACY_BIT, false),
+    DEFINE_PROP_BIT("disable-modern", VirtIOPCIProxy, flags,
+                    VIRTIO_PCI_FLAG_DISABLE_MODERN_BIT, false),
     DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
     DEFINE_PROP_END_OF_LIST(),
 };
diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h
index 2cddd6a..3068a63 100644
--- a/hw/virtio/virtio-pci.h
+++ b/hw/virtio/virtio-pci.h
@@ -63,6 +63,12 @@ typedef struct VirtioBusClass VirtioPCIBusClass;
 #define VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT 1
 #define VIRTIO_PCI_FLAG_USE_IOEVENTFD   (1 << VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT)
 
+/* virtio version flags */
+#define VIRTIO_PCI_FLAG_DISABLE_LEGACY_BIT 2
+#define VIRTIO_PCI_FLAG_DISABLE_MODERN_BIT 3
+#define VIRTIO_PCI_FLAG_DISABLE_LEGACY (1 << VIRTIO_PCI_FLAG_DISABLE_LEGACY_BIT)
+#define VIRTIO_PCI_FLAG_DISABLE_MODERN (1 << VIRTIO_PCI_FLAG_DISABLE_MODERN_BIT)
+
 typedef struct {
     MSIMessage msg;
     int virq;
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [Qemu-devel] [RfC PATCH 02/15] virtio-pci: make QEMU_VIRTIO_PCI_QUEUE_MEM_MULT smaller
  2015-02-23 10:23 [Qemu-devel] [RfC PATCH 00/15] virtio-gpu: Gerd Hoffmann
  2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 01/15] virtio-pci: add flags to enable/disable legacy/modern Gerd Hoffmann
@ 2015-02-23 10:23 ` Gerd Hoffmann
  2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 03/15] virtio-pci: make pci bars configurable Gerd Hoffmann
                   ` (13 subsequent siblings)
  15 siblings, 0 replies; 44+ messages in thread
From: Gerd Hoffmann @ 2015-02-23 10:23 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann, Anthony Liguori, Michael S. Tsirkin

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/virtio/virtio-pci.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index 6c0c650..cd7c777 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -975,7 +975,7 @@ static void virtio_pci_add_mem_cap(VirtIOPCIProxy *proxy,
            cap->cap_len - PCI_CAP_FLAGS);
 }
 
-#define QEMU_VIRTIO_PCI_QUEUE_MEM_MULT 0x10000
+#define QEMU_VIRTIO_PCI_QUEUE_MEM_MULT 0x1000
 
 static uint64_t virtio_pci_common_read(void *opaque, hwaddr addr,
                                        unsigned size)
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [Qemu-devel] [RfC PATCH 03/15] virtio-pci: make pci bars configurable
  2015-02-23 10:23 [Qemu-devel] [RfC PATCH 00/15] virtio-gpu: Gerd Hoffmann
  2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 01/15] virtio-pci: add flags to enable/disable legacy/modern Gerd Hoffmann
  2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 02/15] virtio-pci: make QEMU_VIRTIO_PCI_QUEUE_MEM_MULT smaller Gerd Hoffmann
@ 2015-02-23 10:23 ` Gerd Hoffmann
  2015-03-02 12:30   ` Michael S. Tsirkin
  2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 04/15] virtio-pci: make modern bar 64bit prefetchable Gerd Hoffmann
                   ` (12 subsequent siblings)
  15 siblings, 1 reply; 44+ messages in thread
From: Gerd Hoffmann @ 2015-02-23 10:23 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann, Anthony Liguori, Michael S. Tsirkin

Add msix_bar and modern_mem_bar fields to VirtIOPCIProxy.  They can be
used to configure which pci regions are used for the virtio 1.0 memory
bar and the msix bar.

For legacy/transitional devices the legacy bar is region 0 and the msix
bar is region 1.  Only the modern bar can be configured, and it must be
2 or larger.  Default is 2.

For legacy-free devices the modern bar is region 0 by default and the
msix bar is 2 by default.

Use case: For VirtIOPCIProxy subclasses which need additional pci bars,
such as virtio-vga.  With the new fields they can make sure the regions
do not conflict.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/virtio/virtio-pci.c | 25 +++++++++++++++++++++----
 hw/virtio/virtio-pci.h |  2 ++
 2 files changed, 23 insertions(+), 4 deletions(-)

diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index cd7c777..f97baf2 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -965,8 +965,6 @@ static void virtio_pci_add_mem_cap(VirtIOPCIProxy *proxy,
     PCIDevice *dev = &proxy->pci_dev;
     int offset;
 
-    cap->bar = 2;
-
     offset = pci_add_capability(dev, PCI_CAP_ID_VNDR, 0, cap->cap_len);
     assert(offset > 0);
 
@@ -1243,11 +1241,21 @@ static void virtio_pci_device_plugged(DeviceState *d)
         pci_config_set_class(config, proxy->class_code);
     }
 
+    if (proxy->modern_mem_bar > 5) {
+        proxy->modern_mem_bar = 5;
+    }
+    if (proxy->msix_bar > 5) {
+        proxy->msix_bar = 5;
+    }
     if (legacy) {
         /* legacy and transitional */
         pci_set_word(config + PCI_SUBSYSTEM_VENDOR_ID,
                      pci_get_word(config + PCI_VENDOR_ID));
         pci_set_word(config + PCI_SUBSYSTEM_ID, virtio_bus_get_vdev_id(bus));
+        proxy->msix_bar = 1;
+        if (proxy->modern_mem_bar < 2) {
+            proxy->modern_mem_bar = 2;
+        }
     } else {
         /* pure virtio-1.0 */
         pci_set_word(config + PCI_VENDOR_ID,
@@ -1255,6 +1263,9 @@ static void virtio_pci_device_plugged(DeviceState *d)
         pci_set_word(config + PCI_DEVICE_ID,
                      0x1040 + virtio_bus_get_vdev_id(bus));
         pci_config_set_revision(config, 1);
+        if (proxy->msix_bar == proxy->modern_mem_bar) {
+            proxy->msix_bar = (proxy->msix_bar + 2) % 6;
+        }
     }
     config[PCI_INTERRUPT_PIN] = 1;
 
@@ -1263,24 +1274,28 @@ static void virtio_pci_device_plugged(DeviceState *d)
         struct virtio_pci_cap common = {
             .cfg_type = VIRTIO_PCI_CAP_COMMON_CFG,
             .cap_len = sizeof common,
+            .bar = proxy->modern_mem_bar,
             .offset = cpu_to_le32(0x0),
             .length = cpu_to_le32(0x1000),
         };
         struct virtio_pci_cap isr = {
             .cfg_type = VIRTIO_PCI_CAP_ISR_CFG,
             .cap_len = sizeof isr,
+            .bar = proxy->modern_mem_bar,
             .offset = cpu_to_le32(0x1000),
             .length = cpu_to_le32(0x1000),
         };
         struct virtio_pci_cap device = {
             .cfg_type = VIRTIO_PCI_CAP_DEVICE_CFG,
             .cap_len = sizeof device,
+            .bar = proxy->modern_mem_bar,
             .offset = cpu_to_le32(0x2000),
             .length = cpu_to_le32(0x1000),
         };
         struct virtio_pci_notify_cap notify = {
             .cap.cfg_type = VIRTIO_PCI_CAP_NOTIFY_CFG,
             .cap.cap_len = sizeof notify,
+            .cap.bar = proxy->modern_mem_bar,
             .cap.offset = cpu_to_le32(0x3000),
             .cap.length = cpu_to_le32(QEMU_VIRTIO_PCI_QUEUE_MEM_MULT *
                                       VIRTIO_PCI_QUEUE_MAX),
@@ -1359,12 +1374,14 @@ static void virtio_pci_device_plugged(DeviceState *d)
                               QEMU_VIRTIO_PCI_QUEUE_MEM_MULT *
                               VIRTIO_PCI_QUEUE_MAX);
         memory_region_add_subregion(&proxy->modern_bar, 0x3000, &proxy->notify);
-        pci_register_bar(&proxy->pci_dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY,
+        pci_register_bar(&proxy->pci_dev, proxy->modern_mem_bar,
+                         PCI_BASE_ADDRESS_SPACE_MEMORY,
                          &proxy->modern_bar);
     }
 
     if (proxy->nvectors &&
-        msix_init_exclusive_bar(&proxy->pci_dev, proxy->nvectors, 1)) {
+        msix_init_exclusive_bar(&proxy->pci_dev, proxy->nvectors,
+                                proxy->msix_bar)) {
         error_report("unable to init msix vectors to %" PRIu32,
                      proxy->nvectors);
         proxy->nvectors = 0;
diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h
index 3068a63..a273c33 100644
--- a/hw/virtio/virtio-pci.h
+++ b/hw/virtio/virtio-pci.h
@@ -102,6 +102,8 @@ struct VirtIOPCIProxy {
     uint32_t flags;
     uint32_t class_code;
     uint32_t nvectors;
+    uint32_t msix_bar;
+    uint32_t modern_mem_bar;
     uint64_t host_features;
     uint32_t dfselect;
     uint32_t gfselect;
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [Qemu-devel] [RfC PATCH 04/15] virtio-pci: make modern bar 64bit prefetchable
  2015-02-23 10:23 [Qemu-devel] [RfC PATCH 00/15] virtio-gpu: Gerd Hoffmann
                   ` (2 preceding siblings ...)
  2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 03/15] virtio-pci: make pci bars configurable Gerd Hoffmann
@ 2015-02-23 10:23 ` Gerd Hoffmann
  2015-03-02 12:33   ` Michael S. Tsirkin
  2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 05/15] virtio-gpu/2d: add hardware spec include file Gerd Hoffmann
                   ` (11 subsequent siblings)
  15 siblings, 1 reply; 44+ messages in thread
From: Gerd Hoffmann @ 2015-02-23 10:23 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann, Anthony Liguori, Michael S. Tsirkin

Modern bar is made prefetchable.  In case it is configured to use one of
the bars 0, 2, or 4 (which by default is the case) it is also configured
as 64bit region.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/virtio/virtio-pci.c | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index f97baf2..96b3692 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -1263,7 +1263,8 @@ static void virtio_pci_device_plugged(DeviceState *d)
         pci_set_word(config + PCI_DEVICE_ID,
                      0x1040 + virtio_bus_get_vdev_id(bus));
         pci_config_set_revision(config, 1);
-        if (proxy->msix_bar == proxy->modern_mem_bar) {
+        if ((proxy->msix_bar == proxy->modern_mem_bar) ||
+            (proxy->msix_bar == proxy->modern_mem_bar+1)) {
             proxy->msix_bar = (proxy->msix_bar + 2) % 6;
         }
     }
@@ -1301,6 +1302,7 @@ static void virtio_pci_device_plugged(DeviceState *d)
                                       VIRTIO_PCI_QUEUE_MAX),
             .notify_off_multiplier = cpu_to_le32(QEMU_VIRTIO_PCI_QUEUE_MEM_MULT),
         };
+        uint32_t modern_mem_attr;
 
         static const MemoryRegionOps common_ops = {
             .read = virtio_pci_common_read,
@@ -1374,9 +1376,13 @@ static void virtio_pci_device_plugged(DeviceState *d)
                               QEMU_VIRTIO_PCI_QUEUE_MEM_MULT *
                               VIRTIO_PCI_QUEUE_MAX);
         memory_region_add_subregion(&proxy->modern_bar, 0x3000, &proxy->notify);
+        modern_mem_attr = (PCI_BASE_ADDRESS_SPACE_MEMORY |
+                           PCI_BASE_ADDRESS_MEM_PREFETCH);
+        if (!(proxy->modern_mem_bar % 2)) {
+            modern_mem_attr |= PCI_BASE_ADDRESS_MEM_TYPE_64;
+        }
         pci_register_bar(&proxy->pci_dev, proxy->modern_mem_bar,
-                         PCI_BASE_ADDRESS_SPACE_MEMORY,
-                         &proxy->modern_bar);
+                         modern_mem_attr, &proxy->modern_bar);
     }
 
     if (proxy->nvectors &&
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [Qemu-devel] [RfC PATCH 05/15] virtio-gpu/2d: add hardware spec include file
  2015-02-23 10:23 [Qemu-devel] [RfC PATCH 00/15] virtio-gpu: Gerd Hoffmann
                   ` (3 preceding siblings ...)
  2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 04/15] virtio-pci: make modern bar 64bit prefetchable Gerd Hoffmann
@ 2015-02-23 10:23 ` Gerd Hoffmann
  2015-02-25 20:04   ` Max Reitz
  2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 06/15] virtio-gpu/2d: add virtio gpu core code Gerd Hoffmann
                   ` (10 subsequent siblings)
  15 siblings, 1 reply; 44+ messages in thread
From: Gerd Hoffmann @ 2015-02-23 10:23 UTC (permalink / raw)
  To: qemu-devel; +Cc: Dave Airlie, Gerd Hoffmann

This patch adds the header file with structs and defines for
the virtio based gpu device.  Covers 2d operations only.

Written by Dave Airlie and Gerd Hoffmann.

Signed-off-by: Dave Airlie <airlied@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 include/hw/virtio/virtgpu_hw.h | 203 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 203 insertions(+)
 create mode 100644 include/hw/virtio/virtgpu_hw.h

diff --git a/include/hw/virtio/virtgpu_hw.h b/include/hw/virtio/virtgpu_hw.h
new file mode 100644
index 0000000..d6641e8
--- /dev/null
+++ b/include/hw/virtio/virtgpu_hw.h
@@ -0,0 +1,203 @@
+/*
+ * Virtio GPU Device
+ *
+ * Copyright Red Hat, Inc. 2013-2014
+ *
+ * Authors:
+ *     Dave Airlie <airlied@redhat.com>
+ *     Gerd Hoffmann <kraxel@redhat.com>
+ *
+ * This header is BSD licensed so anyone can use the definitions
+ * to implement compatible drivers/servers:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of IBM nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL IBM OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef VIRTIO_GPU_HW_H
+#define VIRTIO_GPU_HW_H
+
+enum virtio_gpu_ctrl_type {
+    VIRTIO_GPU_UNDEFINED = 0,
+
+    /* 2d commands */
+    VIRTIO_GPU_CMD_GET_DISPLAY_INFO = 0x0100,
+    VIRTIO_GPU_CMD_RESOURCE_CREATE_2D,
+    VIRTIO_GPU_CMD_RESOURCE_UNREF,
+    VIRTIO_GPU_CMD_SET_SCANOUT,
+    VIRTIO_GPU_CMD_RESOURCE_FLUSH,
+    VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D,
+    VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING,
+    VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING,
+
+    /* cursor commands */
+    VIRTIO_GPU_CMD_UPDATE_CURSOR = 0x0300,
+    VIRTIO_GPU_CMD_MOVE_CURSOR,
+
+    /* success responses */
+    VIRTIO_GPU_RESP_OK_NODATA = 0x1100,
+    VIRTIO_GPU_RESP_OK_DISPLAY_INFO,
+
+    /* error responses */
+    VIRTIO_GPU_RESP_ERR_UNSPEC = 0x1200,
+    VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY,
+    VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID,
+    VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID,
+    VIRTIO_GPU_RESP_ERR_INVALID_CONTEXT_ID,
+    VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER,
+};
+
+#define VIRTIO_GPU_FLAG_FENCE (1 << 0)
+
+struct virtio_gpu_ctrl_hdr {
+    uint32_t type;
+    uint32_t flags;
+    uint64_t fence_id;
+    uint32_t ctx_id;
+    uint32_t padding;
+};
+
+/* data passed in the cursor vq */
+
+struct virtio_gpu_cursor_pos {
+    uint32_t scanout_id;
+    uint32_t x, y;
+    uint32_t padding;
+};
+
+/* VIRTIO_GPU_CMD_UPDATE_CURSOR, VIRTIO_GPU_CMD_MOVE_CURSOR */
+struct virtio_gpu_update_cursor {
+    struct virtio_gpu_ctrl_hdr hdr;
+    struct virtio_gpu_cursor_pos pos;  /* update & move */
+    uint32_t resource_id;           /* update only */
+    uint32_t hot_x;                 /* update only */
+    uint32_t hot_y;                 /* update only */
+    uint32_t padding;
+};
+
+/* data passed in the control vq, 2d related */
+
+struct virtio_gpu_rect {
+    uint32_t x, y;
+    uint32_t width;
+    uint32_t height;
+};
+
+/* VIRTIO_GPU_CMD_RESOURCE_UNREF */
+struct virtio_gpu_resource_unref {
+    struct virtio_gpu_ctrl_hdr hdr;
+    uint32_t resource_id;
+    uint32_t padding;
+};
+
+/* VIRTIO_GPU_CMD_RESOURCE_CREATE_2D: create a 2d resource with a format */
+struct virtio_gpu_resource_create_2d {
+    struct virtio_gpu_ctrl_hdr hdr;
+    uint32_t resource_id;
+    uint32_t format;
+    uint32_t width;
+    uint32_t height;
+};
+
+/* VIRTIO_GPU_CMD_SET_SCANOUT */
+struct virtio_gpu_set_scanout {
+    struct virtio_gpu_ctrl_hdr hdr;
+    struct virtio_gpu_rect r;
+    uint32_t scanout_id;
+    uint32_t resource_id;
+};
+
+/* VIRTIO_GPU_CMD_RESOURCE_FLUSH */
+struct virtio_gpu_resource_flush {
+    struct virtio_gpu_ctrl_hdr hdr;
+    struct virtio_gpu_rect r;
+    uint32_t resource_id;
+    uint32_t padding;
+};
+
+/* VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D: simple transfer to_host */
+struct virtio_gpu_transfer_to_host_2d {
+    struct virtio_gpu_ctrl_hdr hdr;
+    struct virtio_gpu_rect r;
+    uint64_t offset;
+    uint32_t resource_id;
+    uint32_t padding;
+};
+
+struct virtio_gpu_mem_entry {
+    uint64_t addr;
+    uint32_t length;
+    uint32_t padding;
+};
+
+/* VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING */
+struct virtio_gpu_resource_attach_backing {
+    struct virtio_gpu_ctrl_hdr hdr;
+    uint32_t resource_id;
+    uint32_t nr_entries;
+};
+
+/* VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING */
+struct virtio_gpu_resource_detach_backing {
+    struct virtio_gpu_ctrl_hdr hdr;
+    uint32_t resource_id;
+    uint32_t padding;
+};
+
+/* VIRTIO_GPU_RESP_OK_DISPLAY_INFO */
+#define VIRTIO_GPU_MAX_SCANOUTS 16
+struct virtio_gpu_resp_display_info {
+    struct virtio_gpu_ctrl_hdr hdr;
+    struct virtio_gpu_display_one {
+        struct virtio_gpu_rect r;
+        uint32_t enabled;
+        uint32_t flags;
+    } pmodes[VIRTIO_GPU_MAX_SCANOUTS];
+};
+
+#define VIRTIO_GPU_EVENT_DISPLAY (1 << 0)
+
+struct virtio_gpu_config {
+    uint32_t events_read;
+    uint32_t events_clear;
+    uint32_t num_scanouts;
+    uint32_t reserved;
+};
+
+/* simple formats for fbcon/X use */
+enum virtio_gpu_formats {
+    VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM  = 1,
+    VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM  = 2,
+    VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM  = 3,
+    VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM  = 4,
+
+    VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM  = 67,
+    VIRTIO_GPU_FORMAT_X8B8G8R8_UNORM  = 68,
+
+    VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM  = 121,
+    VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM  = 134,
+
+};
+
+#endif
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [Qemu-devel] [RfC PATCH 06/15] virtio-gpu/2d: add virtio gpu core code
  2015-02-23 10:23 [Qemu-devel] [RfC PATCH 00/15] virtio-gpu: Gerd Hoffmann
                   ` (4 preceding siblings ...)
  2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 05/15] virtio-gpu/2d: add hardware spec include file Gerd Hoffmann
@ 2015-02-23 10:23 ` Gerd Hoffmann
  2015-02-26 16:08   ` Max Reitz
  2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 07/15] virtio-gpu-pci: add virtio pci support Gerd Hoffmann
                   ` (9 subsequent siblings)
  15 siblings, 1 reply; 44+ messages in thread
From: Gerd Hoffmann @ 2015-02-23 10:23 UTC (permalink / raw)
  To: qemu-devel
  Cc: Dave Airlie, Gerd Hoffmann, Anthony Liguori, Michael S. Tsirkin

This patch adds the core code for virtio gpu emulation,
covering 2d support.

Written by Dave Airlie and Gerd Hoffmann.

Signed-off-by: Dave Airlie <airlied@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/display/Makefile.objs       |   2 +
 hw/display/virtio-gpu.c        | 903 +++++++++++++++++++++++++++++++++++++++++
 include/hw/virtio/virtio-gpu.h | 147 +++++++
 trace-events                   |  14 +
 4 files changed, 1066 insertions(+)
 create mode 100644 hw/display/virtio-gpu.c
 create mode 100644 include/hw/virtio/virtio-gpu.h

diff --git a/hw/display/Makefile.objs b/hw/display/Makefile.objs
index 7ed76a9..6990634 100644
--- a/hw/display/Makefile.objs
+++ b/hw/display/Makefile.objs
@@ -33,3 +33,5 @@ obj-$(CONFIG_CG3) += cg3.o
 obj-$(CONFIG_VGA) += vga.o
 
 common-obj-$(CONFIG_QXL) += qxl.o qxl-logger.o qxl-render.o
+
+obj-$(CONFIG_VIRTIO) += virtio-gpu.o
diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
new file mode 100644
index 0000000..514f71f
--- /dev/null
+++ b/hw/display/virtio-gpu.c
@@ -0,0 +1,903 @@
+/*
+ * Virtio GPU Device
+ *
+ * Copyright Red Hat, Inc. 2013-2014
+ *
+ * Authors:
+ *     Dave Airlie <airlied@redhat.com>
+ *     Gerd Hoffmann <kraxel@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu-common.h"
+#include "qemu/iov.h"
+#include "ui/console.h"
+#include "trace.h"
+#include "hw/virtio/virtio.h"
+#include "hw/virtio/virtio-gpu.h"
+#include "hw/virtio/virtio-bus.h"
+
+static struct virtio_gpu_simple_resource*
+virtio_gpu_find_resource(VirtIOGPU *g, uint32_t resource_id);
+
+static void update_cursor_data_simple(VirtIOGPU *g,
+                                      struct virtio_gpu_scanout *s,
+                                      uint32_t resource_id)
+{
+    struct virtio_gpu_simple_resource *res;
+    uint32_t pixels;
+
+    res = virtio_gpu_find_resource(g, resource_id);
+    if (!res) {
+        return;
+    }
+
+    pixels = s->current_cursor->width * s->current_cursor->height;
+    memcpy(s->current_cursor->data,
+           pixman_image_get_data(res->image),
+           pixels * sizeof(uint32_t));
+}
+
+static void update_cursor(VirtIOGPU *g, struct virtio_gpu_update_cursor *cursor)
+{
+    struct virtio_gpu_scanout *s;
+
+    if (cursor->pos.scanout_id >= g->conf.max_outputs) {
+        return;
+    }
+    s = &g->scanout[cursor->pos.scanout_id];
+
+    if (cursor->hdr.type != VIRTIO_GPU_CMD_MOVE_CURSOR) {
+        if (!s->current_cursor) {
+            s->current_cursor = cursor_alloc(64, 64);
+        }
+
+        s->current_cursor->hot_x = cursor->hot_x;
+        s->current_cursor->hot_y = cursor->hot_y;
+
+        if (cursor->resource_id > 0) {
+            update_cursor_data_simple(g, s, cursor->resource_id);
+        }
+        dpy_cursor_define(s->con, s->current_cursor);
+    }
+    dpy_mouse_set(s->con, cursor->pos.x, cursor->pos.y,
+                  cursor->resource_id ? 1 : 0);
+}
+
+static void virtio_gpu_get_config(VirtIODevice *vdev, uint8_t *config)
+{
+    VirtIOGPU *g = VIRTIO_GPU(vdev);
+    memcpy(config, &g->virtio_config, sizeof(g->virtio_config));
+}
+
+static void virtio_gpu_set_config(VirtIODevice *vdev, const uint8_t *config)
+{
+    VirtIOGPU *g = VIRTIO_GPU(vdev);
+    struct virtio_gpu_config vgconfig;
+
+    memcpy(&vgconfig, config, sizeof(g->virtio_config));
+
+    if (vgconfig.events_clear) {
+        g->virtio_config.events_read &= ~vgconfig.events_clear;
+    }
+}
+
+static uint64_t virtio_gpu_get_features(VirtIODevice *vdev, uint64_t features)
+{
+    return features;
+}
+
+static void virtio_gpu_set_features(VirtIODevice *vdev, uint64_t features)
+{
+}
+
+static void virtio_gpu_notify_event(VirtIOGPU *g, uint32_t event_type)
+{
+    g->virtio_config.events_read |= event_type;
+    virtio_notify_config(&g->parent_obj);
+}
+
+static struct virtio_gpu_simple_resource *
+virtio_gpu_find_resource(VirtIOGPU *g, uint32_t resource_id)
+{
+    struct virtio_gpu_simple_resource *res;
+
+    QTAILQ_FOREACH(res, &g->reslist, next) {
+        if (res->resource_id == resource_id) {
+            return res;
+        }
+    }
+    return NULL;
+}
+
+void virtio_gpu_ctrl_response(VirtIOGPU *g,
+                              struct virtio_gpu_ctrl_command *cmd,
+                              struct virtio_gpu_ctrl_hdr *resp,
+                              size_t resp_len)
+{
+    size_t s;
+
+    if (cmd->cmd_hdr.flags & VIRTIO_GPU_FLAG_FENCE) {
+        resp->flags |= VIRTIO_GPU_FLAG_FENCE;
+        resp->fence_id = cmd->cmd_hdr.fence_id;
+        resp->ctx_id = cmd->cmd_hdr.ctx_id;
+    }
+    s = iov_from_buf(cmd->elem.in_sg, cmd->elem.in_num, 0, resp, resp_len);
+    if (s != resp_len) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: response size incorrect %zu vs %zu\n",
+                      __func__, s, resp_len);
+    }
+    virtqueue_push(cmd->vq, &cmd->elem, s);
+    virtio_notify(VIRTIO_DEVICE(g), cmd->vq);
+    cmd->finished = true;
+}
+
+void virtio_gpu_ctrl_response_nodata(VirtIOGPU *g,
+                                     struct virtio_gpu_ctrl_command *cmd,
+                                     enum virtio_gpu_ctrl_type type)
+{
+    struct virtio_gpu_ctrl_hdr resp;
+
+    memset(&resp, 0, sizeof(resp));
+    resp.type = type;
+    virtio_gpu_ctrl_response(g, cmd, &resp, sizeof(resp));
+}
+
+static void
+virtio_gpu_fill_display_info(VirtIOGPU *g,
+                             struct virtio_gpu_resp_display_info *dpy_info)
+{
+    int i;
+
+    for (i = 0; i < g->conf.max_outputs; i++) {
+        if (g->enabled_output_bitmask & (1 << i)) {
+            dpy_info->pmodes[i].enabled = 1;
+            dpy_info->pmodes[i].r.width = g->req_state[i].width;
+            dpy_info->pmodes[i].r.height = g->req_state[i].height;
+        }
+    }
+}
+
+void virtio_gpu_get_display_info(VirtIOGPU *g,
+                                 struct virtio_gpu_ctrl_command *cmd)
+{
+    struct virtio_gpu_resp_display_info display_info;
+
+    trace_virtio_gpu_cmd_get_display_info();
+    memset(&display_info, 0, sizeof(display_info));
+    display_info.hdr.type = VIRTIO_GPU_RESP_OK_DISPLAY_INFO;
+    virtio_gpu_fill_display_info(g, &display_info);
+    virtio_gpu_ctrl_response(g, cmd, &display_info.hdr,
+                             sizeof(display_info));
+}
+
+static pixman_format_code_t get_pixman_format(uint32_t virtio_gpu_format)
+{
+    switch (virtio_gpu_format) {
+#ifdef HOST_WORDS_BIGENDIAN
+    case VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM:
+        return PIXMAN_b8g8r8x8;
+    case VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM:
+        return PIXMAN_b8g8r8a8;
+    case VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM:
+        return PIXMAN_x8r8g8b8;
+    case VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM:
+        return PIXMAN_a8r8g8b8;
+    case VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM:
+        return PIXMAN_r8g8b8x8;
+    case VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM:
+        return PIXMAN_r8g8b8a8;
+    case VIRTIO_GPU_FORMAT_X8B8G8R8_UNORM:
+        return PIXMAN_x8b8g8r8;
+    case VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM:
+        return PIXMAN_a8b8g8r8;
+#else
+    case VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM:
+        return PIXMAN_x8r8g8b8;
+    case VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM:
+        return PIXMAN_a8r8g8b8;
+    case VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM:
+        return PIXMAN_b8g8r8x8;
+    case VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM:
+        return PIXMAN_b8g8r8a8;
+    case VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM:
+        return PIXMAN_x8b8g8r8;
+    case VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM:
+        return PIXMAN_a8b8g8r8;
+    case VIRTIO_GPU_FORMAT_X8B8G8R8_UNORM:
+        return PIXMAN_r8g8b8x8;
+    case VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM:
+        return PIXMAN_r8g8b8a8;
+#endif
+    default:
+        return 0;
+    }
+}
+
+static void virtio_gpu_resource_create_2d(VirtIOGPU *g,
+                                          struct virtio_gpu_ctrl_command *cmd)
+{
+    pixman_format_code_t pformat;
+    struct virtio_gpu_simple_resource *res;
+    struct virtio_gpu_resource_create_2d c2d;
+
+    VIRTIO_GPU_FILL_CMD(c2d);
+    trace_virtio_gpu_cmd_res_create_2d(c2d.resource_id, c2d.format,
+                                       c2d.width, c2d.height);
+
+    res = virtio_gpu_find_resource(g, c2d.resource_id);
+    if (res) {
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: resource already exists %d\n",
+                      __func__, c2d.resource_id);
+        cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
+        return;
+    }
+
+    res = g_new0(struct virtio_gpu_simple_resource, 1);
+
+    res->width = c2d.width;
+    res->height = c2d.height;
+    res->format = c2d.format;
+    res->resource_id = c2d.resource_id;
+
+    pformat = get_pixman_format(c2d.format);
+    if (!pformat) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: host couldn't handle guest format %d\n",
+                      __func__, c2d.format);
+        cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
+        return;
+    }
+    res->image = pixman_image_create_bits(pformat,
+                                          c2d.width,
+                                          c2d.height,
+                                          NULL, 0);
+
+    if (!res->image) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: resource creation failed %d %d %d\n",
+                      __func__, c2d.resource_id, c2d.width, c2d.height);
+        g_free(res);
+        cmd->error = VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY;
+        return;
+    }
+
+    QTAILQ_INSERT_HEAD(&g->reslist, res, next);
+}
+
+static void virtio_gpu_resource_destroy(VirtIOGPU *g,
+                                        struct virtio_gpu_simple_resource *res)
+{
+    pixman_image_unref(res->image);
+    QTAILQ_REMOVE(&g->reslist, res, next);
+    g_free(res);
+}
+
+static void virtio_gpu_resource_unref(VirtIOGPU *g,
+                                      struct virtio_gpu_ctrl_command *cmd)
+{
+    struct virtio_gpu_simple_resource *res;
+    struct virtio_gpu_resource_unref unref;
+
+    VIRTIO_GPU_FILL_CMD(unref);
+    trace_virtio_gpu_cmd_res_unref(unref.resource_id);
+
+    res = virtio_gpu_find_resource(g, unref.resource_id);
+    if (!res) {
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal resource specified %d\n",
+                      __func__, unref.resource_id);
+        cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
+        return;
+    }
+    virtio_gpu_resource_destroy(g, res);
+}
+
+static void virtio_gpu_transfer_to_host_2d(VirtIOGPU *g,
+                                           struct virtio_gpu_ctrl_command *cmd)
+{
+    struct virtio_gpu_simple_resource *res;
+    int h;
+    uint32_t src_offset, dst_offset, stride;
+    int bpp;
+    pixman_format_code_t format;
+    struct virtio_gpu_transfer_to_host_2d t2d;
+
+    VIRTIO_GPU_FILL_CMD(t2d);
+    trace_virtio_gpu_cmd_res_xfer_toh_2d(t2d.resource_id);
+
+    res = virtio_gpu_find_resource(g, t2d.resource_id);
+    if (!res || !res->iov) {
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal resource specified %d\n",
+                      __func__, t2d.resource_id);
+        cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
+        return;
+    }
+
+    if (t2d.r.x > res->width ||
+        t2d.r.y > res->height ||
+        t2d.r.width > res->width ||
+        t2d.r.height > res->height ||
+        t2d.r.x + t2d.r.width > res->width ||
+        t2d.r.y + t2d.r.height > res->height) {
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: transfer bounds outside resource"
+                      " bounds for resource %d: %d %d %d %d vs %d %d\n",
+                      __func__, t2d.resource_id, t2d.r.x, t2d.r.y,
+                      t2d.r.width, t2d.r.height, res->width, res->height);
+        cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
+        return;
+    }
+
+    format = pixman_image_get_format(res->image);
+    bpp = (PIXMAN_FORMAT_BPP(format) + 7) / 8;
+    stride = pixman_image_get_stride(res->image);
+
+    if (t2d.offset || t2d.r.x || t2d.r.y ||
+        t2d.r.width != pixman_image_get_width(res->image)) {
+        void *img_data = pixman_image_get_data(res->image);
+        for (h = 0; h < t2d.r.height; h++) {
+            src_offset = t2d.offset + stride * h;
+            dst_offset = (t2d.r.y + h) * stride + (t2d.r.x * bpp);
+
+            iov_to_buf(res->iov, res->iov_cnt, src_offset,
+                       (uint8_t *)img_data
+                       + dst_offset, t2d.r.width * bpp);
+        }
+    } else {
+        iov_to_buf(res->iov, res->iov_cnt, 0,
+                   pixman_image_get_data(res->image),
+                   pixman_image_get_stride(res->image)
+                   * pixman_image_get_height(res->image));
+    }
+}
+
+static void virtio_gpu_resource_flush(VirtIOGPU *g,
+                                      struct virtio_gpu_ctrl_command *cmd)
+{
+    struct virtio_gpu_simple_resource *res;
+    struct virtio_gpu_resource_flush rf;
+    pixman_region16_t flush_region;
+    int i;
+
+    VIRTIO_GPU_FILL_CMD(rf);
+    trace_virtio_gpu_cmd_res_flush(rf.resource_id,
+                                   rf.r.width, rf.r.height, rf.r.x, rf.r.y);
+
+    res = virtio_gpu_find_resource(g, rf.resource_id);
+    if (!res) {
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal resource specified %d\n",
+                      __func__, rf.resource_id);
+        cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
+        return;
+    }
+
+    if (rf.r.x > res->width ||
+        rf.r.y > res->height ||
+        rf.r.width > res->width ||
+        rf.r.height > res->height ||
+        rf.r.x + rf.r.width > res->width ||
+        rf.r.y + rf.r.height > res->height) {
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: flush bounds outside resource"
+                      " bounds for resource %d: %d %d %d %d vs %d %d\n",
+                      __func__, rf.resource_id, rf.r.x, rf.r.y,
+                      rf.r.width, rf.r.height, res->width, res->height);
+        cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
+        return;
+    }
+
+    pixman_region_init_rect(&flush_region,
+                            rf.r.x, rf.r.y, rf.r.width, rf.r.height);
+    for (i = 0; i < VIRTIO_GPU_MAX_SCANOUT; i++) {
+        struct virtio_gpu_scanout *scanout;
+        pixman_region16_t region, finalregion;
+        pixman_box16_t *extents;
+
+        if (!(res->scanout_bitmask & (1 << i))) {
+            continue;
+        }
+        scanout = &g->scanout[i];
+
+        pixman_region_init(&finalregion);
+        pixman_region_init_rect(&region, scanout->x, scanout->y,
+                                scanout->width, scanout->height);
+
+        pixman_region_intersect(&finalregion, &flush_region, &region);
+        pixman_region_translate(&finalregion, -scanout->x, -scanout->y);
+        extents = pixman_region_extents(&finalregion);
+        /* work out the area we need to update for each console */
+        dpy_gfx_update(g->scanout[i].con,
+                       extents->x1, extents->y1,
+                       extents->x2 - extents->x1,
+                       extents->y2 - extents->y1);
+
+        pixman_region_fini(&region);
+        pixman_region_fini(&finalregion);
+    }
+    pixman_region_fini(&flush_region);
+}
+
+static void virtio_gpu_set_scanout(VirtIOGPU *g,
+                                   struct virtio_gpu_ctrl_command *cmd)
+{
+    struct virtio_gpu_simple_resource *res;
+    struct virtio_gpu_scanout *scanout;
+    pixman_format_code_t format;
+    uint32_t offset;
+    int bpp;
+    struct virtio_gpu_set_scanout ss;
+
+    VIRTIO_GPU_FILL_CMD(ss);
+    trace_virtio_gpu_cmd_set_scanout(ss.scanout_id, ss.resource_id,
+                                     ss.r.width, ss.r.height, ss.r.x, ss.r.y);
+
+    res = virtio_gpu_find_resource(g, ss.resource_id);
+    g->enable = 1;
+    if (ss.resource_id == 0) {
+        scanout = &g->scanout[ss.scanout_id];
+        if (g->scanout[ss.scanout_id].resource_id) {
+            res = virtio_gpu_find_resource(g, scanout->resource_id);
+            if (res) {
+                res->scanout_bitmask &= ~(1 << ss.scanout_id);
+            }
+        }
+        if (ss.scanout_id == 0 ||
+            ss.scanout_id >= g->conf.max_outputs) {
+            qemu_log_mask(LOG_GUEST_ERROR,
+                          "%s: illegal scanout id specified %d",
+                          __func__, ss.scanout_id);
+            cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID;
+            return;
+        }
+        dpy_gfx_replace_surface(g->scanout[ss.scanout_id].con, NULL);
+        scanout->ds = NULL;
+        scanout->width = 0;
+        scanout->height = 0;
+        return;
+    }
+
+    /* create a surface for this scanout */
+    if (ss.scanout_id >= VIRTIO_GPU_MAX_SCANOUT ||
+        ss.scanout_id >= g->conf.max_outputs) {
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal scanout id specified %d",
+                      __func__, ss.scanout_id);
+        cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID;
+        return;
+    }
+    if (!res) {
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal resource specified %d\n",
+                      __func__, ss.resource_id);
+        cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
+        return;
+    }
+
+    if (ss.r.x > res->width ||
+        ss.r.y > res->height ||
+        ss.r.width > res->width ||
+        ss.r.height > res->height ||
+        ss.r.x + ss.r.width > res->width ||
+        ss.r.y + ss.r.height > res->height) {
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal scanout %d bounds for"
+                      " resource %d, (%d,%d)+%d,%d vs %d %d\n",
+                      __func__, ss.scanout_id, ss.resource_id, ss.r.x, ss.r.y,
+                      ss.r.width, ss.r.height, res->width, res->height);
+        cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
+        return;
+    }
+
+    scanout = &g->scanout[ss.scanout_id];
+
+    format = pixman_image_get_format(res->image);
+    bpp = (PIXMAN_FORMAT_BPP(format) + 7) / 8;
+    offset = (ss.r.x * bpp) + ss.r.y * pixman_image_get_stride(res->image);
+    if (!scanout->ds || surface_data(scanout->ds)
+        != ((uint8_t *)pixman_image_get_data(res->image) + offset) ||
+        scanout->width != ss.r.width ||
+        scanout->height != ss.r.height) {
+        /* realloc the surface ptr */
+        scanout->ds = qemu_create_displaysurface_from
+            (ss.r.width, ss.r.height, format,
+             pixman_image_get_stride(res->image),
+             (uint8_t *)pixman_image_get_data(res->image) + offset);
+        if (!scanout->ds) {
+            cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
+            return;
+        }
+        dpy_gfx_replace_surface(g->scanout[ss.scanout_id].con, scanout->ds);
+    }
+
+    res->scanout_bitmask |= (1 << ss.scanout_id);
+    scanout->resource_id = ss.resource_id;
+    scanout->x = ss.r.x;
+    scanout->y = ss.r.y;
+    scanout->width = ss.r.width;
+    scanout->height = ss.r.height;
+}
+
+int virtio_gpu_create_mapping_iov(struct virtio_gpu_resource_attach_backing *ab,
+                                  struct virtio_gpu_ctrl_command *cmd,
+                                  struct iovec **iov)
+{
+    struct virtio_gpu_mem_entry *ents;
+    size_t esize, s;
+    int i;
+
+    esize = sizeof(*ents) * ab->nr_entries;
+    ents = g_malloc(esize);
+    s = iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num,
+                   sizeof(*ab), ents, esize);
+    if (s != esize) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: command data size incorrect %zu vs %zu\n",
+                      __func__, s, esize);
+        g_free(ents);
+        return -1;
+    }
+
+    *iov = g_malloc0(sizeof(struct iovec) * ab->nr_entries);
+    for (i = 0; i < ab->nr_entries; i++) {
+        hwaddr len = ents[i].length;
+        (*iov)[i].iov_len = ents[i].length;
+        (*iov)[i].iov_base = cpu_physical_memory_map(ents[i].addr, &len, 1);
+        if (!(*iov)[i].iov_base || len != ents[i].length) {
+            qemu_log_mask(LOG_GUEST_ERROR, "%s: failed to map MMIO memory for"
+                          " resource %d element %d\n",
+                          __func__, ab->resource_id, i);
+            virtio_gpu_cleanup_mapping_iov(*iov, i);
+            g_free(ents);
+            g_free(*iov);
+            *iov = NULL;
+            return -1;
+        }
+    }
+    g_free(ents);
+    return 0;
+}
+
+void virtio_gpu_cleanup_mapping_iov(struct iovec *iov, uint32_t count)
+{
+    int i;
+
+    for (i = 0; i < count; i++) {
+        cpu_physical_memory_unmap(iov[i].iov_base, iov[i].iov_len, 1,
+                                  iov[i].iov_len);
+    }
+}
+
+static void virtio_gpu_cleanup_mapping(struct virtio_gpu_simple_resource *res)
+{
+    virtio_gpu_cleanup_mapping_iov(res->iov, res->iov_cnt);
+    g_free(res->iov);
+    res->iov = NULL;
+    res->iov_cnt = 0;
+}
+
+static void
+virtio_gpu_resource_attach_backing(VirtIOGPU *g,
+                                   struct virtio_gpu_ctrl_command *cmd)
+{
+    struct virtio_gpu_simple_resource *res;
+    struct virtio_gpu_resource_attach_backing ab;
+    int ret;
+
+    VIRTIO_GPU_FILL_CMD(ab);
+    trace_virtio_gpu_cmd_res_back_attach(ab.resource_id);
+
+    res = virtio_gpu_find_resource(g, ab.resource_id);
+    if (!res) {
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal resource specified %d\n",
+                      __func__, ab.resource_id);
+        cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
+        return;
+    }
+
+    ret = virtio_gpu_create_mapping_iov(&ab, cmd, &res->iov);
+    if (ret != 0) {
+        cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
+        return;
+    }
+
+    res->iov_cnt = ab.nr_entries;
+}
+
+static void
+virtio_gpu_resource_detach_backing(VirtIOGPU *g,
+                                   struct virtio_gpu_ctrl_command *cmd)
+{
+    struct virtio_gpu_simple_resource *res;
+    struct virtio_gpu_resource_detach_backing detach;
+
+    VIRTIO_GPU_FILL_CMD(detach);
+    trace_virtio_gpu_cmd_res_back_detach(detach.resource_id);
+
+    res = virtio_gpu_find_resource(g, detach.resource_id);
+    if (!res || !res->iov) {
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal resource specified %d\n",
+                      __func__, detach.resource_id);
+        cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
+        return;
+    }
+    virtio_gpu_cleanup_mapping(res);
+}
+
+static void virtio_gpu_simple_process_cmd(VirtIOGPU *g,
+                                          struct virtio_gpu_ctrl_command *cmd)
+{
+    VIRTIO_GPU_FILL_CMD(cmd->cmd_hdr);
+
+    switch (cmd->cmd_hdr.type) {
+    case VIRTIO_GPU_CMD_GET_DISPLAY_INFO:
+        virtio_gpu_get_display_info(g, cmd);
+        break;
+    case VIRTIO_GPU_CMD_RESOURCE_CREATE_2D:
+        virtio_gpu_resource_create_2d(g, cmd);
+        break;
+    case VIRTIO_GPU_CMD_RESOURCE_UNREF:
+        virtio_gpu_resource_unref(g, cmd);
+        break;
+    case VIRTIO_GPU_CMD_RESOURCE_FLUSH:
+        virtio_gpu_resource_flush(g, cmd);
+        break;
+    case VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D:
+        virtio_gpu_transfer_to_host_2d(g, cmd);
+        break;
+    case VIRTIO_GPU_CMD_SET_SCANOUT:
+        virtio_gpu_set_scanout(g, cmd);
+        break;
+    case VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING:
+        virtio_gpu_resource_attach_backing(g, cmd);
+        break;
+    case VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING:
+        virtio_gpu_resource_detach_backing(g, cmd);
+        break;
+    default:
+        cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
+        break;
+    }
+    if (!cmd->finished) {
+        virtio_gpu_ctrl_response_nodata(g, cmd, cmd->error ? cmd->error :
+                                        VIRTIO_GPU_RESP_OK_NODATA);
+    }
+}
+
+static void virtio_gpu_handle_ctrl_cb(VirtIODevice *vdev, VirtQueue *vq)
+{
+    VirtIOGPU *g = VIRTIO_GPU(vdev);
+    qemu_bh_schedule(g->ctrl_bh);
+}
+
+static void virtio_gpu_handle_cursor_cb(VirtIODevice *vdev, VirtQueue *vq)
+{
+    VirtIOGPU *g = VIRTIO_GPU(vdev);
+    qemu_bh_schedule(g->cursor_bh);
+}
+
+static void virtio_gpu_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
+{
+    VirtIOGPU *g = VIRTIO_GPU(vdev);
+    struct virtio_gpu_ctrl_command *cmd;
+
+    if (!virtio_queue_ready(vq)) {
+        return;
+    }
+
+    cmd = g_new(struct virtio_gpu_ctrl_command, 1);
+    while (virtqueue_pop(vq, &cmd->elem)) {
+        cmd->vq = vq;
+        cmd->error = 0;
+        cmd->finished = false;
+        g->stats.requests++;
+
+        virtio_gpu_simple_process_cmd(g, cmd);
+        if (!cmd->finished) {
+            QTAILQ_INSERT_TAIL(&g->fenceq, cmd, next);
+            g->stats.inflight++;
+            if (g->stats.max_inflight < g->stats.inflight) {
+                g->stats.max_inflight = g->stats.inflight;
+            }
+            fprintf(stderr, "inflight: %3d (+)\r", g->stats.inflight);
+            cmd = g_new(struct virtio_gpu_ctrl_command, 1);
+        }
+    }
+    g_free(cmd);
+}
+
+static void virtio_gpu_ctrl_bh(void *opaque)
+{
+    VirtIOGPU *g = opaque;
+    virtio_gpu_handle_ctrl(&g->parent_obj, g->ctrl_vq);
+}
+
+static void virtio_gpu_handle_cursor(VirtIODevice *vdev, VirtQueue *vq)
+{
+    VirtIOGPU *g = VIRTIO_GPU(vdev);
+    VirtQueueElement elem;
+    size_t s;
+    struct virtio_gpu_update_cursor cursor_info;
+
+    if (!virtio_queue_ready(vq)) {
+        return;
+    }
+    while (virtqueue_pop(vq, &elem)) {
+        s = iov_to_buf(elem.out_sg, elem.out_num, 0,
+                       &cursor_info, sizeof(cursor_info));
+        if (s != sizeof(cursor_info)) {
+            qemu_log_mask(LOG_GUEST_ERROR,
+                          "%s: cursor size incorrect %zu vs %zu\n",
+                          __func__, s, sizeof(cursor_info));
+        } else {
+            update_cursor(g, &cursor_info);
+        }
+        virtqueue_push(vq, &elem, 0);
+        virtio_notify(vdev, vq);
+    }
+}
+
+static void virtio_gpu_cursor_bh(void *opaque)
+{
+    VirtIOGPU *g = opaque;
+    virtio_gpu_handle_cursor(&g->parent_obj, g->cursor_vq);
+}
+
+static void virtio_gpu_invalidate_display(void *opaque)
+{
+}
+
+static void virtio_gpu_update_display(void *opaque)
+{
+}
+
+static void virtio_gpu_text_update(void *opaque, console_ch_t *chardata)
+{
+}
+
+static int virtio_gpu_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info)
+{
+    VirtIOGPU *g = opaque;
+
+    if (idx > g->conf.max_outputs) {
+        return -1;
+    }
+
+    g->req_state[idx].x = info->xoff;
+    g->req_state[idx].y = info->yoff;
+    g->req_state[idx].width = info->width;
+    g->req_state[idx].height = info->height;
+
+    if (info->width && info->height) {
+        g->enabled_output_bitmask |= (1 << idx);
+    } else {
+        g->enabled_output_bitmask &= ~(1 << idx);
+    }
+
+    /* send event to guest */
+    virtio_gpu_notify_event(g, VIRTIO_GPU_EVENT_DISPLAY);
+    return 0;
+}
+
+const GraphicHwOps virtio_gpu_ops = {
+    .invalidate = virtio_gpu_invalidate_display,
+    .gfx_update = virtio_gpu_update_display,
+    .text_update = virtio_gpu_text_update,
+    .ui_info = virtio_gpu_ui_info,
+};
+
+static void virtio_gpu_device_realize(DeviceState *qdev, Error **errp)
+{
+    VirtIODevice *vdev = VIRTIO_DEVICE(qdev);
+    VirtIOGPU *g = VIRTIO_GPU(qdev);
+    int i;
+
+    g->config_size = sizeof(struct virtio_gpu_config);
+    g->virtio_config.num_scanouts = g->conf.max_outputs;
+    virtio_init(VIRTIO_DEVICE(g), "virtio-gpu", VIRTIO_ID_GPU,
+                g->config_size);
+
+    g->req_state[0].width = 1024;
+    g->req_state[0].height = 768;
+
+    g->ctrl_vq   = virtio_add_queue(vdev, 256, virtio_gpu_handle_ctrl_cb);
+    g->cursor_vq = virtio_add_queue(vdev, 256, virtio_gpu_handle_cursor_cb);
+
+    g->ctrl_bh = qemu_bh_new(virtio_gpu_ctrl_bh, g);
+    g->cursor_bh = qemu_bh_new(virtio_gpu_cursor_bh, g);
+    QTAILQ_INIT(&g->reslist);
+    QTAILQ_INIT(&g->fenceq);
+
+    g->enabled_output_bitmask = 1;
+    g->qdev = qdev;
+
+    for (i = 0; i < g->conf.max_outputs; i++) {
+        g->scanout[i].con =
+            graphic_console_init(DEVICE(g), i, &virtio_gpu_ops, g);
+        if (i > 0) {
+            dpy_gfx_replace_surface(g->scanout[i].con, NULL);
+        }
+    }
+}
+
+static void virtio_gpu_instance_init(Object *obj)
+{
+}
+
+static void virtio_gpu_reset(VirtIODevice *vdev)
+{
+    VirtIOGPU *g = VIRTIO_GPU(vdev);
+    struct virtio_gpu_simple_resource *res, *tmp;
+    int i;
+
+    g->enable = 0;
+
+    QTAILQ_FOREACH_SAFE(res, &g->reslist, next, tmp) {
+        virtio_gpu_resource_destroy(g, res);
+    }
+    for (i = 0; i < g->conf.max_outputs; i++) {
+#if 0
+        g->req_state[i].x = 0;
+        g->req_state[i].y = 0;
+        if (i == 0) {
+            g->req_state[0].width = 1024;
+            g->req_state[0].height = 768;
+        } else {
+            g->req_state[i].width = 0;
+            g->req_state[i].height = 0;
+        }
+#endif
+        g->scanout[i].resource_id = 0;
+        g->scanout[i].width = 0;
+        g->scanout[i].height = 0;
+        g->scanout[i].x = 0;
+        g->scanout[i].y = 0;
+        g->scanout[i].ds = NULL;
+    }
+    g->enabled_output_bitmask = 1;
+}
+
+static Property virtio_gpu_properties[] = {
+    DEFINE_VIRTIO_GPU_PROPERTIES(VirtIOGPU, conf),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void virtio_gpu_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
+
+    vdc->realize = virtio_gpu_device_realize;
+    vdc->get_config = virtio_gpu_get_config;
+    vdc->set_config = virtio_gpu_set_config;
+    vdc->get_features = virtio_gpu_get_features;
+    vdc->set_features = virtio_gpu_set_features;
+
+    vdc->reset = virtio_gpu_reset;
+
+    dc->props = virtio_gpu_properties;
+}
+
+static const TypeInfo virtio_gpu_info = {
+    .name = TYPE_VIRTIO_GPU,
+    .parent = TYPE_VIRTIO_DEVICE,
+    .instance_size = sizeof(VirtIOGPU),
+    .instance_init = virtio_gpu_instance_init,
+    .class_init = virtio_gpu_class_init,
+};
+
+static void virtio_register_types(void)
+{
+    type_register_static(&virtio_gpu_info);
+}
+
+type_init(virtio_register_types)
+
+QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctrl_hdr)                != 24);
+QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_update_cursor)           != 56);
+QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_unref)          != 32);
+QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_create_2d)      != 40);
+QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_set_scanout)             != 48);
+QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_flush)          != 48);
+QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_transfer_to_host_2d)     != 56);
+QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_mem_entry)               != 16);
+QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_attach_backing) != 32);
+QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_detach_backing) != 32);
+QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resp_display_info)       != 408);
diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h
new file mode 100644
index 0000000..5d26ca9
--- /dev/null
+++ b/include/hw/virtio/virtio-gpu.h
@@ -0,0 +1,147 @@
+/*
+ * Virtio GPU Device
+ *
+ * Copyright Red Hat, Inc. 2013-2014
+ *
+ * Authors:
+ *     Dave Airlie <airlied@redhat.com>
+ *     Gerd Hoffmann <kraxel@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef _QEMU_VIRTIO_VGA_H
+#define _QEMU_VIRTIO_VGA_H
+
+#include "qemu/queue.h"
+#include "ui/qemu-pixman.h"
+#include "ui/console.h"
+#include "hw/virtio/virtio.h"
+#include "hw/pci/pci.h"
+
+#include "hw/virtio/virtgpu_hw.h"
+#define TYPE_VIRTIO_GPU "virtio-gpu-device"
+#define VIRTIO_GPU(obj)                                        \
+        OBJECT_CHECK(VirtIOGPU, (obj), TYPE_VIRTIO_GPU)
+
+#define VIRTIO_ID_GPU 16
+
+#define VIRTIO_GPU_MAX_RES 16
+
+#define VIRTIO_GPU_MAX_SCANOUT 4
+
+struct virtio_gpu_simple_resource {
+    uint32_t resource_id;
+    uint32_t width;
+    uint32_t height;
+    uint32_t format;
+    struct iovec *iov;
+    unsigned int iov_cnt;
+    uint32_t scanout_bitmask;
+    pixman_image_t *image;
+    QTAILQ_ENTRY(virtio_gpu_simple_resource) next;
+};
+
+struct virtio_gpu_scanout {
+    QemuConsole *con;
+    DisplaySurface *ds;
+    uint32_t width, height;
+    int x, y;
+    int invalidate;
+    uint32_t resource_id;
+    QEMUCursor *current_cursor;
+};
+
+struct virtio_gpu_requested_state {
+    uint32_t width, height;
+    int x, y;
+};
+
+struct virtio_gpu_conf {
+    uint32_t max_outputs;
+};
+
+struct virtio_gpu_ctrl_command {
+    VirtQueueElement elem;
+    VirtQueue *vq;
+    struct virtio_gpu_ctrl_hdr cmd_hdr;
+    uint32_t error;
+    bool finished;
+    QTAILQ_ENTRY(virtio_gpu_ctrl_command) next;
+};
+
+typedef struct VirtIOGPU {
+    VirtIODevice parent_obj;
+
+    QEMUBH *ctrl_bh;
+    QEMUBH *cursor_bh;
+    VirtQueue *ctrl_vq;
+    VirtQueue *cursor_vq;
+
+    int enable;
+
+    int config_size;
+    DeviceState *qdev;
+
+    QTAILQ_HEAD(, virtio_gpu_simple_resource) reslist;
+    QTAILQ_HEAD(, virtio_gpu_ctrl_command) fenceq;
+
+    struct virtio_gpu_scanout scanout[VIRTIO_GPU_MAX_SCANOUT];
+    struct virtio_gpu_requested_state req_state[VIRTIO_GPU_MAX_SCANOUT];
+
+    struct virtio_gpu_conf conf;
+    int enabled_output_bitmask;
+    struct virtio_gpu_config virtio_config;
+
+    QEMUTimer *fence_poll;
+    QEMUTimer *print_stats;
+
+    struct {
+        uint32_t inflight;
+        uint32_t max_inflight;
+        uint32_t requests;
+        uint32_t req_3d;
+        uint32_t bytes_3d;
+    } stats;
+} VirtIOGPU;
+
+extern const GraphicHwOps virtio_gpu_ops;
+
+/* to share between PCI and VGA */
+#define DEFINE_VIRTIO_GPU_PCI_PROPERTIES(_state)               \
+    DEFINE_PROP_BIT("ioeventfd", _state, flags,                \
+                    VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, false), \
+    DEFINE_PROP_UINT32("vectors", _state, nvectors, 3)
+
+#define DEFINE_VIRTIO_GPU_PROPERTIES(_state, _conf_field)               \
+    DEFINE_PROP_UINT32("max_outputs", _state, _conf_field.max_outputs, 2)
+
+#define VIRTIO_GPU_FILL_CMD(out) do {                                   \
+        size_t s;                                                       \
+        s = iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num, 0,          \
+                       &out, sizeof(out));                              \
+        if (s != sizeof(out)) {                                         \
+            qemu_log_mask(LOG_GUEST_ERROR,                              \
+                          "%s: command size incorrect %zu vs %zu\n",    \
+                          __func__, s, sizeof(out));                    \
+            return;                                                     \
+        }                                                               \
+    } while (0)
+
+/* virtio-gpu.c */
+void virtio_gpu_ctrl_response(VirtIOGPU *g,
+                              struct virtio_gpu_ctrl_command *cmd,
+                              struct virtio_gpu_ctrl_hdr *resp,
+                              size_t resp_len);
+void virtio_gpu_ctrl_response_nodata(VirtIOGPU *g,
+                                     struct virtio_gpu_ctrl_command *cmd,
+                                     enum virtio_gpu_ctrl_type type);
+void virtio_gpu_get_display_info(VirtIOGPU *g,
+                                 struct virtio_gpu_ctrl_command *cmd);
+int virtio_gpu_create_mapping_iov(struct virtio_gpu_resource_attach_backing *ab,
+                                  struct virtio_gpu_ctrl_command *cmd,
+                                  struct iovec **iov);
+void virtio_gpu_cleanup_mapping_iov(struct iovec *iov, uint32_t count);
+
+#endif
diff --git a/trace-events b/trace-events
index f87b077..e576c73 100644
--- a/trace-events
+++ b/trace-events
@@ -1163,6 +1163,20 @@ vmware_scratch_read(uint32_t index, uint32_t value) "index %d, value 0x%x"
 vmware_scratch_write(uint32_t index, uint32_t value) "index %d, value 0x%x"
 vmware_setmode(uint32_t w, uint32_t h, uint32_t bpp) "%dx%d @ %d bpp"
 
+# hw/display/virtio-gpu.c
+virtio_gpu_cmd_get_display_info(void) ""
+virtio_gpu_cmd_get_caps(void) ""
+virtio_gpu_cmd_set_scanout(uint32_t id, uint32_t res, uint32_t w, uint32_t h, uint32_t x, uint32_t y) "id %d, res 0x%x, w %d, h %d, x %d, y %d"
+virtio_gpu_cmd_res_create_2d(uint32_t res, uint32_t fmt, uint32_t w, uint32_t h) "res 0x%x, fmt 0x%x, w %d, h %d"
+virtio_gpu_cmd_res_create_3d(uint32_t res, uint32_t fmt, uint32_t w, uint32_t h, uint32_t d) "res 0x%x, fmt 0x%x, w %d, h %d, d %d"
+virtio_gpu_cmd_res_unref(uint32_t res) "res 0x%x"
+virtio_gpu_cmd_res_back_attach(uint32_t res) "res 0x%x"
+virtio_gpu_cmd_res_back_detach(uint32_t res) "res 0x%x"
+virtio_gpu_cmd_res_xfer_toh_2d(uint32_t res) "res 0x%x"
+virtio_gpu_cmd_res_flush(uint32_t res, uint32_t w, uint32_t h, uint32_t x, uint32_t y) "res 0x%x, w %d, h %d, x %d, y %d"
+virtio_gpu_fence_ctrl(uint64_t fence, uint32_t type) "fence 0x%" PRIx64 ", type 0x%x"
+virtio_gpu_fence_resp(uint64_t fence) "fence 0x%" PRIx64
+
 # savevm.c
 qemu_loadvm_state_section(unsigned int section_type) "%d"
 qemu_loadvm_state_section_partend(uint32_t section_id) "%u"
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [Qemu-devel] [RfC PATCH 07/15] virtio-gpu-pci: add virtio pci support
  2015-02-23 10:23 [Qemu-devel] [RfC PATCH 00/15] virtio-gpu: Gerd Hoffmann
                   ` (5 preceding siblings ...)
  2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 06/15] virtio-gpu/2d: add virtio gpu core code Gerd Hoffmann
@ 2015-02-23 10:23 ` Gerd Hoffmann
  2015-02-26 16:25   ` Max Reitz
  2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 08/15] virtio-gpu-pci: virtio-1.0 adaptions [fixup] Gerd Hoffmann
                   ` (8 subsequent siblings)
  15 siblings, 1 reply; 44+ messages in thread
From: Gerd Hoffmann @ 2015-02-23 10:23 UTC (permalink / raw)
  To: qemu-devel
  Cc: Dave Airlie, Gerd Hoffmann, Anthony Liguori, Michael S. Tsirkin

This patch adds virtio-gpu-pci, which is the pci proxy for the virtio
gpu device.  With this patch in place virtio-gpu is functional.  You
need a linux guest with a virtio-gpu driver though, and output will
appear pretty late in boot, once the kernel initialized drm and fbcon.

Written by Dave Airlie and Gerd Hoffmann.

Signed-off-by: Dave Airlie <airlied@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/display/Makefile.objs    |  1 +
 hw/display/virtio-gpu-pci.c | 71 +++++++++++++++++++++++++++++++++++++++++++++
 hw/virtio/virtio-pci.h      | 15 ++++++++++
 include/hw/pci/pci.h        |  1 +
 4 files changed, 88 insertions(+)
 create mode 100644 hw/display/virtio-gpu-pci.c

diff --git a/hw/display/Makefile.objs b/hw/display/Makefile.objs
index 6990634..ab6b791 100644
--- a/hw/display/Makefile.objs
+++ b/hw/display/Makefile.objs
@@ -35,3 +35,4 @@ obj-$(CONFIG_VGA) += vga.o
 common-obj-$(CONFIG_QXL) += qxl.o qxl-logger.o qxl-render.o
 
 obj-$(CONFIG_VIRTIO) += virtio-gpu.o
+obj-$(CONFIG_VIRTIO_PCI) += virtio-gpu-pci.o
diff --git a/hw/display/virtio-gpu-pci.c b/hw/display/virtio-gpu-pci.c
new file mode 100644
index 0000000..77c5e06
--- /dev/null
+++ b/hw/display/virtio-gpu-pci.c
@@ -0,0 +1,71 @@
+/*
+ * Virtio video device
+ *
+ * Copyright Red Hat
+ *
+ * Authors:
+ *  Dave Airlie
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ *
+ */
+#include "hw/pci/pci.h"
+#include "hw/virtio/virtio.h"
+#include "hw/virtio/virtio-bus.h"
+#include "hw/virtio/virtio-pci.h"
+#include "hw/virtio/virtio-gpu.h"
+
+static Property virtio_gpu_pci_properties[] = {
+    DEFINE_VIRTIO_GPU_PROPERTIES(VirtIOGPUPCI, vdev.conf),
+    DEFINE_VIRTIO_GPU_PCI_PROPERTIES(VirtIOPCIProxy),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static int virtio_gpu_pci_init(VirtIOPCIProxy *vpci_dev)
+{
+    VirtIOGPUPCI *vgpu = VIRTIO_GPU_PCI(vpci_dev);
+    DeviceState *vdev = DEVICE(&vgpu->vdev);
+
+    qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
+    if (qdev_init(vdev) < 0) {
+        return -1;
+    }
+    return 0;
+}
+
+static void virtio_gpu_pci_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
+    PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
+
+    set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
+    dc->props = virtio_gpu_pci_properties;
+    k->init = virtio_gpu_pci_init;
+    pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+    pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_GPU;
+    pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
+    pcidev_k->class_id = PCI_CLASS_DISPLAY_OTHER;
+}
+
+static void virtio_gpu_initfn(Object *obj)
+{
+    VirtIOGPUPCI *dev = VIRTIO_GPU_PCI(obj);
+    object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_GPU);
+    object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
+}
+
+static const TypeInfo virtio_gpu_pci_info = {
+    .name = TYPE_VIRTIO_GPU_PCI,
+    .parent = TYPE_VIRTIO_PCI,
+    .instance_size = sizeof(VirtIOGPUPCI),
+    .instance_init = virtio_gpu_initfn,
+    .class_init = virtio_gpu_pci_class_init,
+};
+
+static void virtio_gpu_pci_register_types(void)
+{
+    type_register_static(&virtio_gpu_pci_info);
+}
+type_init(virtio_gpu_pci_register_types)
diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h
index a273c33..edb4752 100644
--- a/hw/virtio/virtio-pci.h
+++ b/hw/virtio/virtio-pci.h
@@ -24,6 +24,7 @@
 #include "hw/virtio/virtio-balloon.h"
 #include "hw/virtio/virtio-bus.h"
 #include "hw/virtio/virtio-9p.h"
+#include "hw/virtio/virtio-gpu.h"
 #ifdef CONFIG_VIRTFS
 #include "hw/9pfs/virtio-9p.h"
 #endif
@@ -39,6 +40,7 @@ typedef struct VirtIOSerialPCI VirtIOSerialPCI;
 typedef struct VirtIONetPCI VirtIONetPCI;
 typedef struct VHostSCSIPCI VHostSCSIPCI;
 typedef struct VirtIORngPCI VirtIORngPCI;
+typedef struct VirtIOGPUPCI VirtIOGPUPCI;
 
 /* virtio-pci-bus */
 
@@ -227,6 +229,19 @@ struct VirtIORngPCI {
     VirtIORNG vdev;
 };
 
+/*
+ * virtio-gpu-pci: This extends VirtioPCIProxy.
+ */
+#define TYPE_VIRTIO_GPU_PCI "virtio-gpu-pci"
+#define VIRTIO_GPU_PCI(obj) \
+        OBJECT_CHECK(VirtIOGPUPCI, (obj), TYPE_VIRTIO_GPU_PCI)
+
+struct VirtIOGPUPCI {
+    VirtIOPCIProxy parent_obj;
+    VirtIOGPU vdev;
+};
+
+
 /* Virtio ABI version, if we increment this, we break the guest driver. */
 #define VIRTIO_PCI_ABI_VERSION          0
 
diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h
index bdee464..4a18ef5 100644
--- a/include/hw/pci/pci.h
+++ b/include/hw/pci/pci.h
@@ -81,6 +81,7 @@
 #define PCI_DEVICE_ID_VIRTIO_SCSI        0x1004
 #define PCI_DEVICE_ID_VIRTIO_RNG         0x1005
 #define PCI_DEVICE_ID_VIRTIO_9P          0x1009
+#define PCI_DEVICE_ID_VIRTIO_GPU         0x1010
 
 #define PCI_VENDOR_ID_REDHAT             0x1b36
 #define PCI_DEVICE_ID_REDHAT_BRIDGE      0x0001
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [Qemu-devel] [RfC PATCH 08/15] virtio-gpu-pci: virtio-1.0 adaptions [fixup]
  2015-02-23 10:23 [Qemu-devel] [RfC PATCH 00/15] virtio-gpu: Gerd Hoffmann
                   ` (6 preceding siblings ...)
  2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 07/15] virtio-gpu-pci: add virtio pci support Gerd Hoffmann
@ 2015-02-23 10:23 ` Gerd Hoffmann
  2015-02-26 16:46   ` Max Reitz
  2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 09/15] virtio-vga: add virtio gpu device with vga compatibility Gerd Hoffmann
                   ` (7 subsequent siblings)
  15 siblings, 1 reply; 44+ messages in thread
From: Gerd Hoffmann @ 2015-02-23 10:23 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann, Anthony Liguori, Michael S. Tsirkin

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/display/virtio-gpu-pci.c | 11 ++++-------
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/hw/display/virtio-gpu-pci.c b/hw/display/virtio-gpu-pci.c
index 77c5e06..791ee8b 100644
--- a/hw/display/virtio-gpu-pci.c
+++ b/hw/display/virtio-gpu-pci.c
@@ -28,10 +28,10 @@ static int virtio_gpu_pci_init(VirtIOPCIProxy *vpci_dev)
     DeviceState *vdev = DEVICE(&vgpu->vdev);
 
     qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
-    if (qdev_init(vdev) < 0) {
-        return -1;
-    }
-    return 0;
+    /* force virtio-1.0 */
+    vpci_dev->flags &= ~VIRTIO_PCI_FLAG_DISABLE_MODERN;
+    vpci_dev->flags |= VIRTIO_PCI_FLAG_DISABLE_LEGACY;
+    return qdev_init(vdev);
 }
 
 static void virtio_gpu_pci_class_init(ObjectClass *klass, void *data)
@@ -43,9 +43,6 @@ static void virtio_gpu_pci_class_init(ObjectClass *klass, void *data)
     set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
     dc->props = virtio_gpu_pci_properties;
     k->init = virtio_gpu_pci_init;
-    pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
-    pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_GPU;
-    pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
     pcidev_k->class_id = PCI_CLASS_DISPLAY_OTHER;
 }
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [Qemu-devel] [RfC PATCH 09/15] virtio-vga: add virtio gpu device with vga compatibility
  2015-02-23 10:23 [Qemu-devel] [RfC PATCH 00/15] virtio-gpu: Gerd Hoffmann
                   ` (7 preceding siblings ...)
  2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 08/15] virtio-gpu-pci: virtio-1.0 adaptions [fixup] Gerd Hoffmann
@ 2015-02-23 10:23 ` Gerd Hoffmann
  2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 10/15] virtio-vga: virtio-1.0 adaptions [fixup] Gerd Hoffmann
                   ` (6 subsequent siblings)
  15 siblings, 0 replies; 44+ messages in thread
From: Gerd Hoffmann @ 2015-02-23 10:23 UTC (permalink / raw)
  To: qemu-devel
  Cc: Dave Airlie, Gerd Hoffmann, Anthony Liguori, Michael S. Tsirkin

This patch adds a virtio-vga device.  It is simliar to virtio-gpu-pci,
but it also adds in vga compatibility, so guests without native
virtio-gpu support can drive the device in vga mode.

Written by Dave Airlie and Gerd Hoffmann.

Signed-off-by: Dave Airlie <airlied@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 default-configs/x86_64-softmmu.mak |   1 +
 hw/display/Makefile.objs           |   1 +
 hw/display/virtio-vga.c            | 153 +++++++++++++++++++++++++++++++++++++
 3 files changed, 155 insertions(+)
 create mode 100644 hw/display/virtio-vga.c

diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak
index e7c2734..75a11c3 100644
--- a/default-configs/x86_64-softmmu.mak
+++ b/default-configs/x86_64-softmmu.mak
@@ -7,6 +7,7 @@ CONFIG_QXL=$(CONFIG_SPICE)
 CONFIG_VGA_ISA=y
 CONFIG_VGA_CIRRUS=y
 CONFIG_VMWARE_VGA=y
+CONFIG_VIRTIO_VGA=y
 CONFIG_VMMOUSE=y
 CONFIG_SERIAL=y
 CONFIG_PARALLEL=y
diff --git a/hw/display/Makefile.objs b/hw/display/Makefile.objs
index ab6b791..3da3f6c 100644
--- a/hw/display/Makefile.objs
+++ b/hw/display/Makefile.objs
@@ -36,3 +36,4 @@ common-obj-$(CONFIG_QXL) += qxl.o qxl-logger.o qxl-render.o
 
 obj-$(CONFIG_VIRTIO) += virtio-gpu.o
 obj-$(CONFIG_VIRTIO_PCI) += virtio-gpu-pci.o
+obj-$(CONFIG_VIRTIO_VGA) += virtio-vga.o
diff --git a/hw/display/virtio-vga.c b/hw/display/virtio-vga.c
new file mode 100644
index 0000000..176821b
--- /dev/null
+++ b/hw/display/virtio-vga.c
@@ -0,0 +1,153 @@
+#include "hw/hw.h"
+#include "hw/pci/pci.h"
+#include "ui/console.h"
+#include "vga_int.h"
+#include "hw/virtio/virtio-pci.h"
+
+/*
+ * virtio-vga: This extends VirtioPCIProxy.
+ */
+#define TYPE_VIRTIO_VGA "virtio-vga"
+#define VIRTIO_VGA(obj) \
+        OBJECT_CHECK(VirtIOVGA, (obj), TYPE_VIRTIO_VGA)
+
+typedef struct VirtIOVGA {
+    VirtIOPCIProxy parent_obj;
+    VirtIOGPU      vdev;
+    VGACommonState vga;
+} VirtIOVGA;
+
+static void virtio_vga_invalidate_display(void *opaque)
+{
+    VirtIOVGA *vvga = opaque;
+
+    if (vvga->vdev.enable) {
+        virtio_gpu_ops.invalidate(&vvga->vdev);
+    } else {
+        vvga->vga.hw_ops->invalidate(&vvga->vga);
+    }
+}
+
+static void virtio_vga_update_display(void *opaque)
+{
+    VirtIOVGA *vvga = opaque;
+
+    if (vvga->vdev.enable) {
+        virtio_gpu_ops.gfx_update(&vvga->vdev);
+    } else {
+        vvga->vga.hw_ops->gfx_update(&vvga->vga);
+    }
+}
+
+static void virtio_vga_text_update(void *opaque, console_ch_t *chardata)
+{
+    VirtIOVGA *vvga = opaque;
+
+    if (vvga->vdev.enable) {
+        if (virtio_gpu_ops.text_update) {
+            virtio_gpu_ops.text_update(&vvga->vdev, chardata);
+        }
+    } else {
+        if (vvga->vga.hw_ops->text_update) {
+            vvga->vga.hw_ops->text_update(&vvga->vga, chardata);
+        }
+    }
+}
+
+static int virtio_vga_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info)
+{
+    VirtIOVGA *vvga = opaque;
+
+    if (virtio_gpu_ops.ui_info) {
+        return virtio_gpu_ops.ui_info(&vvga->vdev, idx, info);
+    }
+    return -1;
+}
+
+static const GraphicHwOps virtio_vga_ops = {
+    .invalidate = virtio_vga_invalidate_display,
+    .gfx_update = virtio_vga_update_display,
+    .text_update = virtio_vga_text_update,
+    .ui_info = virtio_vga_ui_info,
+};
+
+/* VGA device wrapper around PCI device around virtio GPU */
+static int virtio_vga_init(VirtIOPCIProxy *vpci_dev)
+{
+    VirtIOVGA *vvga = VIRTIO_VGA(vpci_dev);
+    VirtIOGPU *g = &vvga->vdev;
+    VGACommonState *vga = &vvga->vga;
+
+    qdev_set_parent_bus(DEVICE(g), BUS(&vpci_dev->bus));
+    if (qdev_init(DEVICE(g)) < 0) {
+        return -1;
+    }
+
+    vga->vram_size_mb = 8;
+    vga_common_init(vga, OBJECT(vpci_dev), false);
+    vga_init(vga, OBJECT(vpci_dev), pci_address_space(&vpci_dev->pci_dev),
+             pci_address_space_io(&vpci_dev->pci_dev), true);
+
+    vga->con = g->scanout[0].con;
+    graphic_console_set_hwops(vga->con, &virtio_vga_ops, vvga);
+
+    pci_register_bar(&vpci_dev->pci_dev, 2,
+                     PCI_BASE_ADDRESS_MEM_PREFETCH, &vga->vram);
+
+    return 0;
+}
+
+static void virtio_vga_reset(DeviceState *dev)
+{
+    VirtIOVGA *vvga = VIRTIO_VGA(dev);
+    vvga->vdev.enable = 0;
+
+    vga_dirty_log_start(&vvga->vga);
+}
+
+static Property virtio_vga_properties[] = {
+    DEFINE_VIRTIO_GPU_PROPERTIES(VirtIOVGA, vdev.conf),
+    DEFINE_VIRTIO_GPU_PCI_PROPERTIES(VirtIOPCIProxy),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void virtio_vga_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
+    PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
+
+    set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
+    dc->props = virtio_vga_properties;
+    dc->reset = virtio_vga_reset;
+    dc->hotpluggable = false;
+
+    k->init = virtio_vga_init;
+    pcidev_k->romfile = "vgabios-virtio.bin";
+    pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+    pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_GPU;
+    pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
+    pcidev_k->class_id = PCI_CLASS_DISPLAY_VGA;
+}
+
+static void virtio_vga_inst_initfn(Object *obj)
+{
+    VirtIOVGA *dev = VIRTIO_VGA(obj);
+    object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_GPU);
+    object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
+}
+
+static TypeInfo virtio_vga_info = {
+    .name          = TYPE_VIRTIO_VGA,
+    .parent        = TYPE_VIRTIO_PCI,
+    .instance_size = sizeof(struct VirtIOVGA),
+    .instance_init = virtio_vga_inst_initfn,
+    .class_init    = virtio_vga_class_init,
+};
+
+static void virtio_vga_register_types(void)
+{
+    type_register_static(&virtio_vga_info);
+}
+
+type_init(virtio_vga_register_types)
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [Qemu-devel] [RfC PATCH 10/15] virtio-vga: virtio-1.0 adaptions [fixup]
  2015-02-23 10:23 [Qemu-devel] [RfC PATCH 00/15] virtio-gpu: Gerd Hoffmann
                   ` (8 preceding siblings ...)
  2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 09/15] virtio-vga: add virtio gpu device with vga compatibility Gerd Hoffmann
@ 2015-02-23 10:23 ` Gerd Hoffmann
  2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 11/15] virtio-vga: add '-vga virtio' support Gerd Hoffmann
                   ` (5 subsequent siblings)
  15 siblings, 0 replies; 44+ messages in thread
From: Gerd Hoffmann @ 2015-02-23 10:23 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann, Anthony Liguori, Michael S. Tsirkin

[root@fedora ~]# bin/lspci -vvs2
00:02.0 VGA compatible controller: Red Hat, Inc Device 1050 (rev 01)
(prog-if 00 [VGA controller])
	Subsystem: Red Hat, Inc Device 1100
	Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR+ FastB2B- DisINTx+
	Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
	Latency: 0
	Interrupt: pin A routed to IRQ 10
	Region 0: Memory at fe800000 (64-bit, prefetchable) [size=512K]
	Region 2: Memory at fe000000 (32-bit, prefetchable) [size=8M]
	Region 4: Memory at febd0000 (32-bit, non-prefetchable) [size=4K]
	Expansion ROM at febc0000 [disabled] [size=64K]
	Capabilities: [84] MSI-X: Enable+ Count=3 Masked-
		Vector table: BAR=4 offset=00000000
		PBA: BAR=4 offset=00000800
	Capabilities: [70] Vendor Specific Information: VirtIO: Notify
		BAR=0 offset=00003000 size=00040000 multiplier=00001000
	Capabilities: [60] Vendor Specific Information: VirtIO: DeviceCfg
		BAR=0 offset=00002000 size=00001000
	Capabilities: [50] Vendor Specific Information: VirtIO: ISR
		BAR=0 offset=00001000 size=00001000
	Capabilities: [40] Vendor Specific Information: VirtIO: CommonCfg
		BAR=0 offset=00000000 size=00001000
	Kernel driver in use: virtio-pci

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/display/virtio-vga.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/hw/display/virtio-vga.c b/hw/display/virtio-vga.c
index 176821b..0e48ba9 100644
--- a/hw/display/virtio-vga.c
+++ b/hw/display/virtio-vga.c
@@ -79,6 +79,12 @@ static int virtio_vga_init(VirtIOPCIProxy *vpci_dev)
     VGACommonState *vga = &vvga->vga;
 
     qdev_set_parent_bus(DEVICE(g), BUS(&vpci_dev->bus));
+    /* force virtio-1.0 */
+    vpci_dev->flags &= ~VIRTIO_PCI_FLAG_DISABLE_MODERN;
+    vpci_dev->flags |= VIRTIO_PCI_FLAG_DISABLE_LEGACY;
+    /* avoid conflicts with vga framebuffer @ bar 2 */
+    vpci_dev->modern_mem_bar = 0;
+    vpci_dev->msix_bar = 4;
     if (qdev_init(DEVICE(g)) < 0) {
         return -1;
     }
@@ -124,9 +130,6 @@ static void virtio_vga_class_init(ObjectClass *klass, void *data)
 
     k->init = virtio_vga_init;
     pcidev_k->romfile = "vgabios-virtio.bin";
-    pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
-    pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_GPU;
-    pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
     pcidev_k->class_id = PCI_CLASS_DISPLAY_VGA;
 }
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [Qemu-devel] [RfC PATCH 11/15] virtio-vga: add '-vga virtio' support
  2015-02-23 10:23 [Qemu-devel] [RfC PATCH 00/15] virtio-gpu: Gerd Hoffmann
                   ` (9 preceding siblings ...)
  2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 10/15] virtio-vga: virtio-1.0 adaptions [fixup] Gerd Hoffmann
@ 2015-02-23 10:23 ` Gerd Hoffmann
  2015-02-24 16:26   ` Marc-André Lureau
  2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 12/15] virtio-vga: add vgabios configuration Gerd Hoffmann
                   ` (4 subsequent siblings)
  15 siblings, 1 reply; 44+ messages in thread
From: Gerd Hoffmann @ 2015-02-23 10:23 UTC (permalink / raw)
  To: qemu-devel
  Cc: Dave Airlie, Paolo Bonzini, Gerd Hoffmann, Anthony Liguori,
	Michael S. Tsirkin

Some convinience fluff:  Add support for '-vga virtio', also add
virtio-vga to the list of vga cards so '-device virtio-vga' will
turn off the default vga.

Written by Dave Airlie and Gerd Hoffmann.

Signed-off-by: Dave Airlie <airlied@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/pci/pci.c            |  2 ++
 include/sysemu/sysemu.h |  2 +-
 vl.c                    | 13 +++++++++++++
 3 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index d508930..3a2b8ad 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -1662,6 +1662,8 @@ PCIDevice *pci_vga_init(PCIBus *bus)
         return pci_create_simple(bus, -1, "VGA");
     case VGA_VMWARE:
         return pci_create_simple(bus, -1, "vmware-svga");
+    case VGA_VIRTIO:
+        return pci_create_simple(bus, -1, "virtio-vga");
     case VGA_NONE:
     default: /* Other non-PCI types. Checking for unsupported types is already
                 done in vl.c. */
diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
index 748d059..1c0e2a6 100644
--- a/include/sysemu/sysemu.h
+++ b/include/sysemu/sysemu.h
@@ -107,7 +107,7 @@ extern int autostart;
 
 typedef enum {
     VGA_NONE, VGA_STD, VGA_CIRRUS, VGA_VMWARE, VGA_XENFB, VGA_QXL,
-    VGA_TCX, VGA_CG3, VGA_DEVICE
+    VGA_TCX, VGA_CG3, VGA_DEVICE, VGA_VIRTIO,
 } VGAInterfaceType;
 
 extern int vga_interface_type;
diff --git a/vl.c b/vl.c
index 8c8f142..27fe972 100644
--- a/vl.c
+++ b/vl.c
@@ -234,6 +234,7 @@ static struct {
     { .driver = "isa-cirrus-vga",       .flag = &default_vga       },
     { .driver = "vmware-svga",          .flag = &default_vga       },
     { .driver = "qxl-vga",              .flag = &default_vga       },
+    { .driver = "virtio-vga",           .flag = &default_vga       },
 };
 
 static QemuOptsList qemu_rtc_opts = {
@@ -1870,6 +1871,11 @@ static bool cg3_vga_available(void)
     return object_class_by_name("cgthree");
 }
 
+static bool virtio_vga_available(void)
+{
+    return object_class_by_name("virtio-vga");
+}
+
 static void select_vgahw (const char *p)
 {
     const char *opts;
@@ -1896,6 +1902,13 @@ static void select_vgahw (const char *p)
             fprintf(stderr, "Error: VMWare SVGA not available\n");
             exit(0);
         }
+    } else if (strstart(p, "virtio", &opts)) {
+        if (virtio_vga_available()) {
+            vga_interface_type = VGA_VIRTIO;
+        } else {
+            fprintf(stderr, "Error: Virtio VGA not available\n");
+            exit(0);
+        }
     } else if (strstart(p, "xenfb", &opts)) {
         vga_interface_type = VGA_XENFB;
     } else if (strstart(p, "qxl", &opts)) {
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [Qemu-devel] [RfC PATCH 12/15] virtio-vga: add vgabios configuration
  2015-02-23 10:23 [Qemu-devel] [RfC PATCH 00/15] virtio-gpu: Gerd Hoffmann
                   ` (10 preceding siblings ...)
  2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 11/15] virtio-vga: add '-vga virtio' support Gerd Hoffmann
@ 2015-02-23 10:23 ` Gerd Hoffmann
  2015-02-26 18:13   ` Max Reitz
  2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 13/15] virtio-vga: add vgabios binary Gerd Hoffmann
                   ` (3 subsequent siblings)
  15 siblings, 1 reply; 44+ messages in thread
From: Gerd Hoffmann @ 2015-02-23 10:23 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

Add seavgabios configuration for virtio-vga,
hook up the new vgabios in the makefiles.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 Makefile               | 2 +-
 roms/Makefile          | 2 +-
 roms/config.vga-virtio | 6 ++++++
 3 files changed, 8 insertions(+), 2 deletions(-)
 create mode 100644 roms/config.vga-virtio

diff --git a/Makefile b/Makefile
index 6817c6f..cc01719 100644
--- a/Makefile
+++ b/Makefile
@@ -337,7 +337,7 @@ bepo    cz
 
 ifdef INSTALL_BLOBS
 BLOBS=bios.bin bios-256k.bin sgabios.bin vgabios.bin vgabios-cirrus.bin \
-vgabios-stdvga.bin vgabios-vmware.bin vgabios-qxl.bin \
+vgabios-stdvga.bin vgabios-vmware.bin vgabios-qxl.bin vgabios-virtio.bin \
 acpi-dsdt.aml q35-acpi-dsdt.aml \
 ppc_rom.bin openbios-sparc32 openbios-sparc64 openbios-ppc QEMU,tcx.bin QEMU,cgthree.bin \
 pxe-e1000.rom pxe-eepro100.rom pxe-ne2k_pci.rom \
diff --git a/roms/Makefile b/roms/Makefile
index 610b534..c76cd5b 100644
--- a/roms/Makefile
+++ b/roms/Makefile
@@ -1,5 +1,5 @@
 
-vgabios_variants := stdvga cirrus vmware qxl isavga
+vgabios_variants := stdvga cirrus vmware qxl isavga virtio
 vgabios_targets  := $(subst -isavga,,$(patsubst %,vgabios-%.bin,$(vgabios_variants)))
 pxerom_variants  := e1000 eepro100 ne2k_pci pcnet rtl8139 virtio
 pxerom_targets   := 8086100e 80861209 10500940 10222000 10ec8139 1af41000
diff --git a/roms/config.vga-virtio b/roms/config.vga-virtio
new file mode 100644
index 0000000..9a78983
--- /dev/null
+++ b/roms/config.vga-virtio
@@ -0,0 +1,6 @@
+CONFIG_BUILD_VGABIOS=y
+CONFIG_VGA_BOCHS=y
+CONFIG_VGA_PCI=y
+CONFIG_OVERRIDE_PCI_ID=y
+CONFIG_VGA_VID=0x1af4
+CONFIG_VGA_DID=0x1010
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [Qemu-devel] [RfC PATCH 13/15] virtio-vga: add vgabios binary
  2015-02-23 10:23 [Qemu-devel] [RfC PATCH 00/15] virtio-gpu: Gerd Hoffmann
                   ` (11 preceding siblings ...)
  2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 12/15] virtio-vga: add vgabios configuration Gerd Hoffmann
@ 2015-02-23 10:23 ` Gerd Hoffmann
  2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 14/15] virtio-gpu: add to display-vga test Gerd Hoffmann
                   ` (2 subsequent siblings)
  15 siblings, 0 replies; 44+ messages in thread
From: Gerd Hoffmann @ 2015-02-23 10:23 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

Add prebuilt vgabios-virtio.bin binary.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 pc-bios/vgabios-virtio.bin | Bin 0 -> 37376 bytes
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 pc-bios/vgabios-virtio.bin

diff --git a/pc-bios/vgabios-virtio.bin b/pc-bios/vgabios-virtio.bin
new file mode 100644
index 0000000000000000000000000000000000000000..7febcb660b23ba1fb6d0d52d9f08458b86cd8c15
GIT binary patch
literal 37376
zcmeHwe|%I$mhbH(B%RRYb|7GbE%Z2m$Otxy7_=pU5D=MQYYaL%Xdt8-H400*NgP86
zCed_47<YGeX5E?H=a1R<acA8p%ewrU9qbS$1kCcw872yYQQ6RK#}L7R5MuJa=TzPP
z5n$f#`|Nvv%?0}2x^?Q*sZ*!Uud1tszgQCb<iR{``1RL*db4Cfz9tHV|35@QZNNK8
z{8G!&w81v-Ekb|ynDBonny(~oZW)@i`E#u^JX#$4RDbu7M>M@Ql%i>P*C+fP;t8>0
zUxLE2Toiaj;|jCzpY}AYu!!bPt4Q4^W(BqerV9T!i%Ix<T_$hl`b<}%{-c1nU(|H=
z0O4cb2`BtZy4Zu>wXOTa(y8?mYw<AEpI)b-gC}FUcvPSh{PBP25&ryM;om3bepEIA
z-R4=v{T>jWXA!0rk1*x+dc>s_7LTaeXw|$kw(bK=z8OD0wEARA$JUQ8{CsPNM-1g#
zJtC0+8}smkcHs}iW8Cdivg1cVV&!DBs5#RI@bUr4GD%5I_iSPmxS?r7V)JK1LqnSI
zpAfT#g#PnOR?*yL75?)g^@`Yh2vr)WE<7qWf1v%PPR}cTBmAvma~HRs!i{GgN6UR^
zNz6MTMyXbL9b)rg)yj8D91CqZx-}qnX|E8@CSTz4zmM%75I+--i<<qj4eC+j=@U;y
zCdi=KDr)+4?@jo%>VMTD^c@!f>7A2|r;~X4{u3j@7O{5(s1m>AU;pn!^SMM(a~4y0
zR2&Op;t~L88BMd$4IY<tC)6JkHJ|DpaUiePgqGEplf9!v&1VTf3aO#V+C%T_KN25)
zhPDq32^09~&kthKnnjM-ok;z?CN5pZ+q^S`exgTwSaL?}qISanmH4m|Z*zt)RfWC6
z)Q^Vy&~UHOaFB2Vq;UnePNXUA=3XEcK|sE5K%(z9Fv@B$3LKg#8q-UQMcqNY_KGQf
zirvD00JyZ7o`xLaQGf`1Ths(n=wX{jG;iESoh^psL-hQ4KZhXhT%6A0i0a1jBzp0v
z6$GCUrjLaQ!q{Zb0O*Q$JPnUps{0eYPgeIQ>9q-_>iz`1?l}_xeD8@_m=1l%Ba^`A
z#=N)P!Mg|1CRyY{Vtw00%@wonlP$+lm%mLkf0~Fsj*I5c&{<R7d)!H5-aGE#ecyy`
z0zQ4mqXwGZZvc}2p4ejsV}TL1i9qpy4|32*18TDW8a3J$$YKN~$T6K4{*M6Sdj~7o
z9XvBY!+LOns0m?V>F)xCAM?@yiFXGN42WOSyb;J^yO`UeH~oYQ4`Q_vEbuH&!V@^w
zSon@G9d!r)azNyU4^xY$CZgsvEzF-|ISbPV5)Co;ZGL1VdFT)`bMK0G%El4pZ$qW%
z@3zt^2ErC`2^eZNzO8vD3jbx{|CnIFklR4_P(JXOFc8y)@W&7ZcZ?{=+4nb#y1)xJ
zh&}ruHDXtSu4(7C9~QfkFsSgiu=FrGh?}TsOOP<<gue~T7K)-RY5U=GS81)9Zs-E&
ztwx{4<In5z`18*g$O+du^a0$sB|*R9rlDWiV*;0HCE|550f7fQ@~p%TtUmvWUSfPr
zC)l|o01`$*@1zS;D;Rl^xRqzd%MrrVOAUe~Rrjtq<GowFuf0Arw3TF=7BMs<el`X@
zjd@*LKHk~^{rEA78Wxe#r!{#&N4RA;(M0C9q;t-|x$W)UVs{$IeB0zr_~-N}Ka$0s
z!vrR|hua7%mEu>RWc!|W00PZ>xG@^2$hIgiu?DTx{U+~?>oZ_juy9~VAg>E^Okq11
zNOO}3nEPp+9+cg&PKja=QVTv*-y&*0&t|PPN$ko&ODI(TX|T?Ww#OjsQ~l$L@N#Oy
zI6vJQ=hSJ{pP9Um)(o0AJY0P_r98j-%A|6L9D0(PGuI^MHWSyq<46$2`?SEQf9R~H
z$A-dCye&|O@1mD0P^aMpF(0MFqWN;7Sc1vP$EvzCNLCG|Rf<v?=DLwAogrHz&&8W3
zHsE9x{U5r69}faw2YN|y2mcokwTj(L0??6WRXE3Bg`NZZSmvYlTQbH^1_5-eB|5gH
z_J{@D5UoxOVCj%ZZR@Fq)`78xjAB(J<2MYo(p2ybT0s>x<qqH>;12%9puyCs{)u&(
zJ2(mWTDFbGG9;V-A}mRNH$dCArO+!X@r;nYI4PPxhi+~9{&*9*&LM;-C4sP=0UF1k
z_+<_{-U`*x<Q|$@KMw9f%hbkk4`_rCP{%Pickt#*c>C6Or4ONuIdiL~8@)G+Js*>(
zZ4Y#N>hp%`+j_P)ch@&>{}^vP4S7R7^=-o69V0i)<5n{Fk%slnSa?149f0i_#!Q0d
ze&So8t4q`deThpSif?s*rP~8N=<rex)`Mvn7BwZTHDFy1h&=~DGxb(?(K|)#IY=Ye
zdSI%jK2hFsP3oQiAxIR<!Y8g$Yz5+B%*2+Xq(hd%CV{8Vki99q><-osiSL1y%bxn&
zvAFl+J|6cgxZ5CyD+c0Oay5BvG2{_l4T+M-9xmjX)I9-%y$*Q~dm7whJ@tj(;65Jr
zLELS)50RzQcic}D?^6_i;|}^j@wJG02xA0fe`K;C5<PfvQkXswbFb)4FOjfZ*m6`c
z0R9E>;462qc2GP{Jr#Z>o;{vVPkHCX(}ACmz?0=h`GR;hU<de*5~}HKb3f+hXib0i
zhGelT8*ebn7x3>q{(W_g9-0TSgmXjXLlNS(IcQOoe0|kqNe;twkm`n8<A>+t|G?uf
z1iXJm@NJV``)tC+{U+adxVw30G-yD*_Q3=(>!4KAp|K`+@aO$3I%LSCp5NL^5<_c_
zpP;r_KdVv#uK`s^+<r(sB@xoSgao9{#|k>%Bli57ac<4)0m6kNM?jy|Tu$<x-oBsM
zz5UnSo~?PksLD-s9z?5h6D_KKtoHL%BO9f0qw&5oV%9}04R`Q+14iAQ-xiBR&0wbQ
zEcZ<|gb+~2N8&oZn{lN2J|%P23uW!`znBAkJ_}FvxeMqgmwpz~PhRNwpzNUmB!jF!
zGqGY!?LDXHCp7uJTbm)jxv7|NGOA`}<>_tXi#cLf22H)cAByxK2A$y@8^M_-(a}&P
z#__)23uV}9ItMoo{RU=hpGZ9__Uywjde9I|YRJ7&>E{fI_M$@g2-pDS%DgGNqB!!o
zYP1v!OzAOF3$qSxKOCXsZbgSABGuQ0VflJ#%4u2BO!jaA^N&f9k8oy)&8kGc<fF+X
zo4Jcf0)xP?@r>~IK`$rhwKGg&^I39Uyj4Vw*lj1C>|H`jfLsY_0t{z@K!~wG()5B|
z>?Y$O_SWLpfWXAPv4@-XvRmQ{Vj>sajA=v-9P~<!)QIpen@r_5EGAi8G)?Tfjr)u&
zfxpzY(fl((H0q#uUr|-qYXpCWfkHhEtZAJ=)B8jd-bO)D*cc_L5hU%-0Ssi}tv!;a
z#$}TgnSO)J#%0rpOn*8eUqv4gVuFL(n0MxFxcfiVuynmkrB<h<Nu5AMlef1?HNMES
zy;VI?z_mOP+UkH<!@lRNgYIC*W%2md15(UiPQ<)Lw19VR1YN@-Olm6&+BHzj?iY`-
za$W>2K<c|kY;H}$UEF$F_%G@87l{@5XD&9I_1Z5GC%v(-5T3DKdm8VXX5U%;A0{8d
zz6j@Aw6Gg8MBXv`%ICHp`BKWNKN$|)Z_((<1hE_S8tDq}cyetRUO_@D_~9JEQ6goM
z=KCo8hHT$B@nVa~H+C3uxJu{34~m-B7^DE=z9V=U=w_e+^2TJi-|SEsz0!PO?Gp;w
z<u66e0eC8iPp_qu{S?0CJSuAXQ_D$xEO5?*@A2n7F}?!4F}RogN#5m~(s57lmTr1N
zJmB?(sg&%!x$<`0Q@kVD&kNe2qKD+84GT+m2meYHGiC8*RfPXYwJ;py9|kS5xJDHb
zc~I^5R53{w5oiM#HLxu!Law3M*w%l5)ahjzsfp%Lk~awv7_{&Sn*6$pRcUHu%fes5
zOQUs9`55?8p>Yxsd~I{>K}7l-+*e;t^g6=OlyL90@HkYuldEAIp}jVMx_v1~2q0~A
zG=@{;Cy}i-<jQx8JNWelay`e8>nZ)E4tG%d8ZH|f-%HSHiQ(@UVnAAiB!`?`KL9;Q
zz3e;zH~6UG`yQ3P@8e8+)ZLBvbMD~ouZ`}#PFAxwgK2OOr4(}ynCGP5qbr%BV5ecv
z5f0m~<44zYn`4Jn=nme5VKr~F2>&5cs4zNY1?%&Aw~eA#s)Q&KgBVSq?1c0pqBrxn
z&moycRQy$hitsZG>?6-Qj#y^L0g6`1`<L8lredm5)OYq`42V_UZBcA8GB5Q00Keym
zf#c~!te3~(XQ{~_mQW(bBlehgp1ce);E$Y_coC^8c7d5wG~~Y!8)N*iiji;zWA8r~
z;r=FW|MPEXGGn<<10qK?KB%HOstb4@FhF^*B<*r6O-a8sScR|%t>uJ8_+UWB)IpOD
zA7uT$!GLd+VJi>}u7YAio>Z&uPbt5}cuyh@)$-lZZlI`dYYv&~+c9(GtOm%?$BUf`
zUl3A0z>&*D1S#a2awPfgN4N)QrgI4^Dh>-1B246DO-Ca#jQCT3rCw!TrI%PB-p|2+
zVGr~jaAy6K=|mFub6S7BB9)RmKKL2_@6T~V;WtcNrDc8ObGd^8!rtNzRsp<O?4=l5
zafao}m^Xy;he$Y;kD_xiE>X&{Rm5QhPIPF64oGk%dZ(AC4z}sFi3y>%Mz~=4jwiX2
z^}3&o078s3>iC8>kQppUf{T?-DMx)LLT7zvE*ObqA7>2VL^R}DkV3BQ)(F)KlMAj$
z16iYj(Nf}(3T{n8TDmUa``Yj-r}bdkDBl6rLfyj$(gY=2Wje20yw4FWl;N$%2%uYh
zNKOtGDd!!{3&)HW3!t>kzLV^MCHelrNQA_thR%id!BLiu?7x0V@-&M^u;Y<L7!;uD
zhYB=_-Q3x&&B%p{)ZZaBS<`3sb;J-z5q}>%0h8+N-SD3qSfBcm@a0N$lEzD5qQ0{L
zAxYzlaM}DD&wzguJpPT{p62Je6Y+W@JTE^Svby8mZ%6Y!`c6*#Yz$ubg?NCV5Mh`$
z2E!ey*B^!^NcK}Y4(x}gAxCx+vxHf(3pY|}Wtgqp3C%&8t$=XDpa2!(6tG)E;J+}4
zz}BKLHiy~<ArcEHKSR#oQY(IPlb|_3UtTv5r5lK7t@{rh`vO=oP4E5=^Xme%A46#<
zpq!~*I|=DhNWf*zn%358)t{QYsUER8uUB(Gig#(dBJ+(f!sMHUS+~-hU|sD^;hZw&
z0NL#iu>>w7e{J&Ae-{%a=c6-pDFJKR`to^h0xF(u8x%FoSP9V<iLotChkl(fj0SYJ
z%y%D28Vi`Gf$;kei<&No7K9BV&?QpO8(qfHjQO{Q$`H&Qk7<?|p(3{7X`|uG=fO}C
zZ@)E^mEdVuI+{lgzvELAhTSYo&_~TEVYYTa(wkh;p1>$KBY~LOhlB(aS2C0q5Ea;&
z|NTm)3MMpvL9<NraRSv!swm5PMq|Muh93}qT0$gMlxT%aH9`<su;Bd}I1$Y&Va2RJ
zF`+q3h@k>0?Ms_9n_GDf>yGQS>r4<?h4~}+q*7WFecj<s$oa%$=g<;ziYz9YUxt|C
zIoFPD3Mr2d#fm3MRji0YmAiv){0E6BnDImE6Rjb=oA;^bC?+NAam2!XftYDpsD;{L
zDWKD(>AW0CXCdEzNUAIE0#}mv2QG5s%SL-`ynmyTbC-Yunh9=Kcns17yID;&8}7^R
zww&Z-?8)%ca?#OB>7_BjkL?EX(b%~|bDD)-&AX7&VzjU!rE&t0lRqE+l-treZWShS
zEqL{c<@_`OEK#fV$7d8PqB=QZ?%88%A@6WE*rXw4*_t#GTK1stYtVEj+wN(|IQwZq
z!w)#e&*q5DlCCG^#U?}ekdF7~W3zyqn!Ho);NJ|vRwa7;E4~0tJFt%jHxDDcXqeck
zZ`2Ws(FA5vf42<@bkagQ3a#+<kP(5mj)EDA3a$D*t$9IA24h~0rM-VL$cS2D!%UHn
z21a@6^DiLJWhQqFcMI<4JPn0bPeXnt%E&(<nbVMG$Nej)uSD#Z&OrGqlmWwu9<(Vm
z10J3m(k&fulAqv#le0WxNbJo4#}Hz_@qi|$E$^H=*o|CZE83vXLbU5c0vB)g&BWxU
zk?_)p^2wCbCZ)b}BX+Ye&HjxLRaBgZTR?Rf!&lsu;hP`-?2mKWIrx9iX<}|4hD@yL
zAtuARFq4NaU6;vl`C96a)?*=H2ev++G!%x=fI-#g_u!r>*`E(K=l6oWBN0)6y<kf{
zV8Bw`fdg5|d~^M=dd`lMNioK2jk1?KDsbweFp=yb+TN?d)OxBn_GsP|;m5#{-mf|A
z@c4aj!u1{4^JvJ&cGW7_HOY63ua|08T%a85cnUqS>qRosnAdaRAH_24N)-mfpV2Zg
zD2S{OL#%Sh`>D@A3gqU9{7Tw(^v}Jd*F0uIYJheWu$kZ+S9|b<(N4~Byip0Ov=2t6
zIy?$iN2NLF6$|}gFne|eh(CnzkBnj7F5cH_%KHuF%|!EAESZg;MY_b20XMKR{2SY8
zP=!b3@_<f0karXkNvyGGFN^`#bCX>u`j5#rLhk%|M`7#HWM>}j-sZiBZ8l%K-t@W#
zhU~%w=Di17YEMSOiS*7<&HDg^q0>ad08-BXfhrmnj_QJ#91^>#(GxjT`i?7P3hVm3
zSSp2xUq9RAxufuqr~Z*qT^xIxeFwu+0d_LlhTuEANdzAYcbfVmZA$&U^aruXGn98G
z^ym=gCFiPnDZuvbILccb_aQp9e-F{=tzyspg&H<>8)>N>#Kw(}_8b-@gy$eqO&6Q{
z32gl*;UjoF^#pQUH^Qy~9Q&R7ZbOrk*wplWjwbUHV7p-FWA%&LP@;5}m@;I-=vRcw
z;$m-7f~0#+2>%gxux*GUnKhVb=Dix$E6^mgvDXKo{0tL&CYHxrzplmhaAW?_7p7wN
z=41BCv8CUI82j^09_RP(>WXF1%CEyCsnS!AiZGcw(uW+%M}${ySvVwB?%-Wa63#cU
zf<{n!`7-G>Nlh1IFo+J$@QkAp@p%n4Z5kHd^o8U`&3*^>aJA00(&9iS`waHeNwY%p
zVwZt6Yyq@w?$}6jts%V@@{8>?Y?JNioqKparCa6?Md};VdCTX#s(A>ZKW#!mH(n68
zLT;OWKt2zv(ZciMR(Lc`Zj-1R(zo`*Y#rCPUVugM7Y5zI`)Ow#PQOfSMb^*j2=<_%
zfh3o8Kloi3gc!hY13b<y)E%rEL1D%S@o=aX$jA|@dI0({2$KqJz(xWZh7KIKS<636
zHW%@QJLn~|WF!4U`|m*l<wn?zX~@mM<MMDWYQI7S+Bc(h5L-8-VuoXyZeaQfxs*p~
zb3`Fv<ghKOM-QTp{h8pxHH^EVx=2~Wl))SwL5QTL1+xq`!JEW_gV}WlZ5*OQWQ!qt
zS}j;C_mB&NSSF8x;tRrEe+(oeDF9EP6G=w#cz6yC#U1<ulzijzG^if4=Cy5wKJPcO
z92+l))P8ba!)Z9O1Jw^77^)&s<ap|lv(AAY*}Biz>I=+0>N9(g+4KzNk{n)lR1dSn
z={wdTLeh6skTKnnlYxv3G`&>!JD;$Lx|3cTct>uzA5+ql2f{z2t(v7_TIT;{?C)di
zb~tv3Qw(-&HT@s47l3x;(7fZzQ;>1+-W8r)-Jj+iU)?{-H^I{iMfPo;0IwZEZ+&8T
ztY;8=;W`*?h6GVA2^+7E8JU5puh(kz&1%h=vYN}Dp;o!rBU*d~f=)W<G008=@&mM;
zN)rHydKj3%muEEGvDpEIOmq6L7p3?{pb6$-f+9d}svvvGHMox0kvC|rXMOOs*o71k
z-0_!Tn&D*tPdyzsDTH^~ln3YN?4Wo8c>5t%moY%R=>z0-b|q#04Ju}=Ysi<uOBgf$
z9Y)<7z6r7nT~mMx99TlHkaY4l$fYa9<ikCNhf)9!rSP1mvCLL?5e@9#`#f875fe5*
zf|@E!)t@GKN2@pYBXrEigf~?r@cQFtlAt??{mbCog?~w*p%nvwD_KaZ8nt(Wo@+@K
zvBd)YdIdVADZgL*l8#jn=PzA=`Eh#cGia`o#FFqAo(2=#Q6p13KTPK;$TPWG@gk4d
zBu~1T<*L<dJ58=BUNdKTL;r>~)Ck9phK8=sInW>AU^B=CY85p-PI#Ktms87caXF#!
zkV_biEz&e_YcF^wnjT3z8pe9eJLe=y7l*O12O%)7Qr|eSm@wgqqO7U}6c#1?v&psE
z`}n4tTr>6B9?ey(*Zxj(P0{OSn3$ezQ+h(PO|CM%)@0f=&9zRi%cMnKmLzMPJ@Q_G
z%|J^0f%e2uwdV49XSyo9xuLW4=FZxKzGUnrB!!U;Z!yE8dtsz(Hlqi}gCNIrdZ95f
z9?TtlVKB6tG4cwog^z<Fp7Tzl{=p#1Sb+T#Ma>sxckrEHgaVq<fwSQknNGk_xhWWa
z7UiXqZtATk{2ja~H-QU_F+ksgT#cF=WoTi{WiIB@kAUEV@C*atNVK8p9?zrb5%a@}
z4O3_(Y&666`l0Qc7L&%#Glw!r`ef!i_5=he6*61tV$GKi(USY^H{!9dPwiE^S^g6!
zxufq)q}xy#mhVuRjee~3V;5`wzzu))4aCjC4JOM5xej%|neI)wQzZgSJY|aTV-{<i
z4^yW_s_j)PxTYI`{=5OGlZV8bXBqfT0tS*syry#*q1kcn6zw6P4FdQ3Cc<yiUpitE
z_icyUroZxQljmYyuh~}y-sM`<R@h8ndNG|Mt<mb};jH7AzQTBWx3u9m04obs=kIq1
z$9w_?ZXP7nw8^e2$x3`B_DqBW31{~-c)Tcll6py?tq{3A7jOrk`-Ho}2IfWdoq0FR
zj?|s+{GRh+nFvs@Qg&qmw>$U~Y!cI^EJAVoo};E^<K#{mS}#mTe2iV_)Hb=DJHqz`
zLrisItDm-P0h5#-2a@Uw(~u|7;@x8$sM`J;xpmF>Uz~_hQbRqi;dozIZcSr>^zdl_
zKA?bn5AF9>YnpEX8c`HHX0XjSnYfrnyRBLd?9t6}MX}3)04$6=umOYS@Rl$9BVoW<
zwAz3#*WjvES&!Y!!9A75#FjnqIrm$_6UCbC<VUZW4Y?C*Dp)8cUSVZd^8u149T2wb
z+Gsv}M*@P32}_AvtoeIJak8JcHpo&QhttD0a8_hPVzjZhKzkY3NWm#L$if4d_w{4(
zV1=laTS5~O<RR72G{`L_kH|hky5UXMjZMPPm*ZH|PIm2sC@o5YKYs>q+Q5TksMjvs
zpHzV&(w7^%S=h`-RX5~yhm*Djwhc{vbBShHaashuQ#81&BlEgx2O6GKm*%?(R@)D&
zjji(rpud0Wn>ZJBK<rAv23GhEbg?J}MVWVne@X|broKhsc!!a<$)i<9GaQ|Gs|Y#}
zshBPr6rAK^$0BJA9IJ8%zuSR?##_ZmYXAyItvEjeTQP-11SxHk7#~2qP%UbL4nV&7
z3Lv*#p894zB|=`up*q-<&P`L_^g|#H%E3{BS;kJtHDgD`?@e{9!0;@BVgI;g8U$_D
z!KwA>tLSMjseY_QlpC}yM-Tv8#opdm@s5%Jse=?i`{%qJX;i{bfvIl_ZOcI%nzf2u
zm30h_v}hY#OYv5vR(&PiYpcFu_1;d0-LfKpo54p*q*NB)%wh_sN9rKB$Pmm5gl<SM
zL`knrA+tA8hM(0}5`Et>0?TpO5`|c#QD9kf`5E6?oGn%{<*eiG;0;&8w^UzA^4%=e
z*o|tn7^eWlo@r0gI(hbE@fbQ-Mu#nFq3nWAz#&WIe77ILVsFGL0Dm(}pYZeEAb?1u
zkw-&F)5b?lY4e9)ZR~=_!ms$)DGNTNfVL&T<a0Wo1#do^f=y$YT5kR{dHZ1;0~M)=
zMGl&_A0d=t&u>74(l^u`9UY-<9c(1u&l;zu%|zMTW4vPSK#qkwj#Og#5e5P|fR{*v
zZ2pXOLrp(~>!7$qht6^SDFLof&A}WAy)C6@`)}#c;;%5JJ*4k=+jH9u@^xEck2-!p
zs+V@E-N6Ssqz=W2MvV6yjxWgrznCWPg6+TAmZ_TNplJ?Tu-2AMbu=Zdy)B8(J7I&<
z+yh38=-GaRNcaRV(8xHV12q~t2c6Z1G~ORmR+(g<*I51>J+0ZnYHIdHWE3A0YtFFt
z`z^n7Tx8=;s_T|M$k`S@+4TF#7(ZdBq*e2$X0iDo=&cre`Yb?(MSgDkz?U-{=lsk+
zx7T;mcI?K}t3kX<|2zNOHecG7HeNFmU-e59u&t$s*n#adOoNoHSpmq1*afXLL?Xh)
zFYgO%^Xg(vCsX$FAH<WPX>^u|BvHZtn&1h&RF+t33kwaZ^}2o&ax`<$>n}lXCp<O1
zzDBNM{{`N}#8(qB1L@#_-1kpoz3ET~_kBG<{}J{!4u+HE+=9JHO*BCw74ySm$G`<n
z3DB|MUOI9>iIo(Jk$P#zsit!ho|}8jF#K!A7m!diBc-uF)8I#Gv9Yem6$b;pgaBKy
zq{yhiX<)9Udy6qV4pX74)=+`JUcgw_6%(tQgPG{2K&+X^T|7x$z$J-4E(4^rNzEpQ
z8sUgJmN30iOZH3Hk06zKiGviByCO~0+S{wrTUBI$7A2F(Asax6+t0xs9Ks>N$-;IE
zB|hl+XK+rMJ@;-5mfuTyf5qoGC*D<lJIT`uGFRAw)88$G0c~245_7g0FOidf7opm{
zD|$DOH-Oze-U(c@ibq*-fzA%_%tP{_)Zvo1BEvRF88-c;$A_X)usV^>Z6WxylA^Bp
z?1-p2<NzzV$j3@hs6*ZMBAok$K?!WXj0aeh!1jmmKqs}grA~dbMB8$R@-(dBxA`Fl
zM3K_)y{~fAN3ZFj8}o^WnvLBz>9w!GaYl9qoO*RKtUTBNB|&sjzNq#IIF*zO)N3Dt
z2iSt4Qn-{u=|E%<kNG~uM;U{9?QFRA*bBm2<c=^^DCP15;0@XQf&|2spW`7njjVs|
zai49=A^t=O9+n@Qcl9Zh{m45Lb`ntPmcwjf`-n6)+_c-ZQNnR{$_I5FvEQEh#U^UO
zFu>9Ue2bB|fhEVpvn5XfbI!vEd;E(N*^8tsOwEB2VmAq$aX^mxwnqpfEU66aVBj>d
zdwd))+||huXkh!c*iDXY6dM4h#RA+dc9Ui{01z9HcUF_vn-f|)i20-Q6T9wo8<U5O
z^zp4^p>s&3AhX|#%|?s?rwm|8C%g0W^}564THx5x2#oeT98v;lhL=eSd+zx%9d#B6
z{t;oiA{K<ZYftKRKh@x|6Wl&R^;in#sD;!5ov^avVU3rC_+OweuvDQ{A9^NLJToMo
zaXh1WhQ2=;S?v8*e0;@cE!2Szc$!VQNJaO3Q@)f|`!+_gu9x&RuY=}r63)f{$WJDX
zhq?J$!=&S40js!AgU!?HEJNIsPg=pN8MnocB?2d@eq6FPvmqVl9Vk`W{Ant^4v4vJ
z-jNutjlMX_3A2V0mp*1_P<IVaS#Ixnsw*-~8&W+7a_tYALa)QOtgxEOv74WRslw7k
zM*HIa9OUm?b8n)6+a0uoC>TEMseUm78KYdQcS<DN?%f6V9v>P>{ia+AXsg`J@O)3>
z(oFFBt0-_IfL|E~47rYVL*y}_xxISbiXkRZyH1kXhUJOmkKHu_%Q3lpGMy2r7*Re7
zG0QwUiSk2JsMJh{NdA`3qwF0KT48qKgyTag<vNb0)Q+LuklHtsLyOF=G`+Sf#brg7
zA|-UU8EY95M9Xex0bFwk8QC}-2|!Tu3#`*!%kv86LzMi0x<qA)=CINhBpL4E2apD|
zW_?8R>tB!z4Y;nDh1tIV36-V=H+%T}4sBSGOkrF8k~{?|{69!1OX)4<^$qX6xyK6h
z>qm>dpGd@Td=Jx+PT^laPV7B@)yoNDZ}KBdLJZ_Y?064iih(<wc1o}XCw7ww5p$20
zQA{_hW^l-Bkwo~N<f8Ifh|QOIpX4L)K5I!n46T>nOs#H0tGlmmg)^21ZVPwt&RWeO
zvIo{sM>4S$HmaBSD!0*Jv>}(hW)vvJX2h4$)#<A~gJk8cU948g+ZjVJ(-<b>OLCDy
zb;*obP0J;o7Gz7-6tm9=qe9>9L3<L1>K7r^2?%;hq!<3>NqE7sjsmPEIjtDR{4}mz
zWLDt*MQMhD`pJXFY#x<NUj!`yE#J5V<H?65X{<<c2alehffdpTg`+gTDRIZ{5Hphc
z_vf9WUaf2j^1Jc8Y&5AQe-+X%Oi06gSO%h&4p+`M%jX;Lyd)Vx1Q(Z$2W%mTZWxUK
zvcB*vz?a_$vuL7r6Cr8dVvr(@`6<w{hrThz7pqW_mo5<zI8;!0mcFuDynYJK+4vrZ
zCZxna+=TbZK9JGu#9b4+?!|BTd+3mjTu$13+BUs*<_LKlRP4GP)uHc<pb6P#rta-x
z55*X=VJKq+s40aY`|~=*`{dlvlqPMv7jE1x@&hFv4vDK#EZ5mgo64<hE5fO4zNtou
zrJQ;`IkgDMDxPJEp%DzDa|)2biwV`2t={L#?bVlcq~2Qd&g!ynJO)SLr#mgYvih>k
zdsFpghi@j+o<PlSAy}Jqd^pc}7ItWeT2a!o+q%t+ydFS|w;H`gArQ`teVt6NM{dJb
z7SB3io`eZ+p!u#}=785ir9vEiuV4NxoG?fI&GPnbGGz#g>z7Z)lOOve^~<Mh#l}!R
z&G9lU_?nHK@J$*M6>i+}J4p}VB>Fyzn(6U2mZ)V;^nz*<xMg>6rwaF7va>lje8sq#
zth?jL%90>+<?S9Ki<i*7L>3)eTjZjqc|_Kt`$AX9`Jgj=Fs9kOR7D6L;geYMaG*J+
zgXWR@q}Yk*!H&dDFfaB8Ln9Mo?GEgQw6DPP5aXE`BDE0u8}0yJ6}q7lW!SF6nF6It
zY~oUDFC<*Ado}@9;FXdDnd?G|=5N{|Z+bl%R^#Z5UiUDn`jV-e&|+xs_>5AhqYoy|
z3Jl*)Kv4b}qG)PeI~Jw$@SI!8_Q8TdoH1A%7CO=!f!K9UW2HkLRUcBrx>Il=QMyQ8
zH`DQfiMqy$O!_rMnvc#7;*Cu%Sz4Z7p_m!^N1S-{wNN(&w(vi>gN>h}cc#S;<tUER
zdLlm(0|aiSvVJY?30m>_eeU{XSG8XE6#QHw6Tj~QIG#{O4deVS4t_OdW-%(uZ<y#?
zOrhIAH*jb0DC)<VC~q`Ggc0Sxm6YRy02~ej?V&+v?=KL~fm311QEJErCA&=J(!)p$
zO;d#Fue4(y(dS0rJC<f($m%nL9Z&+p!lRnY$&}Ua`~;t=*IYL1b$<b*ZCE*xBikH0
z$vDWs<bD2XJe`h6k_rd=0_N~SvD-}n_8uRUQJA*Eh-LQmqrvc*5m9`7w-%lN@5AcU
z!w$e?L^dYhL`^!xHv{^C9jNdF(n|?15W5#L=2zKUK(sX`L{*w8e2bwiZ=p$NH5k#b
ztl&s7hAdaW-fMVm#=fmtIy^VIM(VZaAf)eT<oX;ml|MtSPmQU3S}msFW)qyBx(TC*
z%LO#~JFxX0i#PPqe)5V|nQ*kW?z~0p?qI6_%Ak5h5L9PE;U37f@h^gG9)}kC+(Hgi
zx2b##IZz*%5V{SK6Lr88`Ui_ERj<uUfGbt^w=j>xR@S!9Tp4=pu@U9>xYG67FB8hY
z?Xu{#EeWnsdfoFDDUI}-YjX!5{sjEBhc;MTx?cNn0=Z?WiJ|)~t_gZ=TUz-f*Jymf
zZ+4B*>t<iw(eFQZ+4b7?k@`ymX|4zLx{RwqcK!h~YKL@fg8QCQl|qWh5gv;|GJUl5
z0D{u5kf_V{)EB^*<zQ-{Pw5k3R3L+Q$OI)}*Ir1hK3pBo*tH>SA!Z=>!<Us<#0WcP
z1;}SkDK~S>`$iE?hVg>jk&B(m&BriKtic`oaUUCcc_dBN6ZYyWIQRX+NO$nZzc&=n
zvm@(2BI8Zpy#5U`X|0By`QFip$ol6{;uQa74IF47KYxv2{dxLx8Pq@=Gtjab={#uI
z9lwdE{4b6v2^~IfQ;|G?1cBNQj}kT9(hnyGo7}(zJw#tLcb}5#$vc;pzdS3@OBSlz
zi~T1*6H@p&_MgVHKKvc!LYHIvA7^j1`hCqoGrR%BGdKkcmg9rQtHftaCoMvF_BUWR
zViTUN>Wdbz0_SYQ4-u7RFg52fM>@;_C5<U#xQ{<gVa83^Z?vJj5HSH76k9x;L*fkE
zevymlKFJph^`~+bElbdX04Q4ZNvhc0#w%tN{G8CQ;Gw`IK{JxBCNgl2ByPE3+o%Bt
zw?T9K`_9gYaN!UNsT2~k^d%&1ufGCeLs~txjg|slyn(HH*v!z%R3Ng`l6cuvKAqNa
zf~kCz3m=L8t){<Rr-im_v_vyav>GRwusG}T6GE3X*A05@QB(PyST(gznOtM_+ILM@
zM|DoJsQ5^j$>%}9N5@cbSfaok>~9I}Ho3;@wXG)orT0v<01ug5H|lkl*|zX_VfEw3
z_4t0~g4LC&zp@?46R4q#FfDQ1WuiD9{-u4?A+{eIm*ODwNeZc&S*{S;X5NctuyB}y
zC-(8|pflvCeW%DVX;@CPcs%?MSaw!E{>=Z441~zMUmW@o{8-EfQ!<TYjKAo_5lozq
z$ju0iCE~c_7iGui(JgK5ptqgP{CQ#_WnhxV$ew+j27=d6OOB5<bS&j6SshPydq-J@
z=VGqa<hz9gsrl0syaHL(Bv71@j_1KU%|@PjUUO}rA_*}eyb~$RymuHngikew>C_Bj
z+;!*fe>5Xfx&!C6uvX-^fuYGM@(JH0!T%YTV)S_^P~RK~A!efghKt&&#22ynqKui1
zt@FeH!h`yy*3hp9#qM1!{r^PL|9&!yBTnewZYrNiV)!xAeZSDiAYIWQo^?MZNx>Yb
zy#V!9>bX#ji44Mxrt<j^<~kqC(^6VLI}6wxuo!}ie14ghHqKPhWQpbOV8g$WPGh_o
zp*bYSSOpNbx|ycPJ|oo@SmkMzxXs3VZY+l$x=a$X^FP;b*kK?~zZUW`3SxWlUEzL9
z=znSksFeR<bZmy_@u2}hOYd5ghX2`sxPEt=xjV5d9by%pX~18vPj~Pk1y9-$KHIN&
z@^02^r<lrTxg2`!H=65Pdflr$W!GQ|m`}t$VHE`-o5?j<ubmIQFy7>H>UB@ZdCtI>
zKn3Na;ZjX6&xYECMG`pi8lLJJ;a$Ey&z0=`KIx>FHP05T_FWalAp8*n4qwqyvg`}1
z$6t^TzE6Twg0bOQ>X|q<CHg!<OA3#Z#TN)unySJx46P+%8yk^O#(%mAFAHp-2uGx_
z0y0CHNffXAJ)5T;r{Ktu^dUg_jMX99<FhW6kgU`~U5S#xJYSjO;mEx0CiaUxL?{qo
zJMY+goTm8K>o(vm%{`Sgnt#6@QZ`GxK_31GvHNXaa~qIn3N1~fHSM~CTs>s6oL-^7
z64qQ+@3hcQO|IE`Z2>0bJ0{m%^jU>#j$T)XuaWAxeK)oD;9KP!Pz*-AQLNqfULsD|
z!P8ANg_HRX1*NKAuO};{vy&ghY^m4kzm|epV!={G*(UF|*Xz}n6MWNQe%Hc9vWCa0
zr)pq;y=^mx?~re}lp3B4ZIjoHA1GX$0QrC?0otE}MoQ0<_khpMxyxpm_HU+r<<Ps7
zfh6w@0@q}bVU*#d!EA0tmb>#33@2?yhhB;RyLdMdTZz%n^uGbr_I*9!CkY{tWoqKm
zaS(~mj8(U^gN-j~I==}|BpZ%8xV-1V&SCX~kd&#|<PMJ!yZ@Rw{U6{o8xsBZ<X(;r
zy^U5CTy=pa;bn@6>~LsqgF~~BCN$y<yxAbl7M%}W^A+=DJT`uDxH2;`1+OE>qGPWV
zOalFc&=R0u!|3lrWE8r^6qCbz5#MU`Z$%oDsK#2m@C(Qsd4jw*9<y`8nM$Oz=)WL9
zGlNNJ`azP|J(1e+H~*3V<70kGoM4`O1Xp#lI%G5abAONu7~|V|N;NE+LJ2sMZ)7GG
z-Lmz7OdQ>c2hPGw$3r5)&7!g07=B)^OZruzKb_P?&#(s+`u8F9_bqWHl;=gl{<r=O
z;b_HO9Q5NnxC;3Rojp8B?EXG;>hHj*tBmSXCo!0~AgrKd<?_Yz7c6<O;2uXs)|`^(
ze2&tRm8A~v`jzXxB@c4#Eq-ujLsHM8&4ZgCto*~*;cu{6;O1kM1^7;5xp*{r;+CUZ
zJB0sp(0oStJCRbZhK_;&r;5#&W%B>MA$Rc6pzxoXlmhjE|0W*t-t<ZCV;}tAU=zT$
z1zCgt9&9#X`?IgEf$d2Dz(nDmxs^6Lb{&Vm>=8fAv3q`qyT1ZQW&G=4jr?mY_<0Ok
z)$fLn>A&CR*^&b{(_b{zv&B7~nm9Z^%$W?ig0Hv#TFm*$AdD+qvrf-eYS36TRXqN<
zXJ{SN$j~|mUQlO^)LA2S)<~T-QfH0mY%4k&auTFnJT~b_nRoRD&&sFDO1w`!w{~@j
zwqaGtQ?s12#bb|YuNu$JmD;OoRzAPFl&Vk>d7iZrB@wNgb;t1Xopa*r@4PFnJZl&{
zVUNM*Ts5pbTO(rEtu6Cv4#%>>?|wH8cgM>6rZ}@I9FA4$Uaan`<$ZM-?z1Z#CF))#
z@6@#HX$7M0tJcYKnYtINCQnltC>(<CX<C`rx5_c4?4BvB?@7}ho&WH%CCe5&W;mXH
z-dnQ%d8~($_3PKJcdRb)mK1wSRy$UDCGfY<vc&7a5^@l?9aAdOv;yzS^<GDGVL7I4
zC|O_j^xEgq<kmE;giuoJG;P^h$MOYvj)hAK+)HFvVr6kjq?g+qVr6OR)6aVxt5z02
z>+r61$jMF9BCYOmtXeG`Q=E5H+(SPzr&QbqV4z<e2UIFnJ+*T6>h<?gec97L0HLcL
z`3usthfAJYyMcO$P(R=6EqQL8m)@a6^uM-vrMHAfSmq@%Haxx3vF^F&9L1<35aJ^`
zpN)|d8zhj?PI8KvQnHei42^eM?yZhHoU>*{-YqQIP*S>f9hek(MFX6_dgVH>3N&t*
z>6pc1W-6b4UaWPjFZnZHNtyQ^<~TvC0XUvt>vf2=zULJK_%)^|3Rvu0zaDeI4Zsf~
z&FffM?0tGeiDTVL4_E_6I*3~(Wo0}%V$;gij^Z_7?9<OXJW!2mo-Qt93~Ab8G#6`u
zkm*`*|1@fUtD}5nnPc_SWyLGkuPy;C1tq1B90w%93);&Z*M^#3%HjroFMPUeUFpgf
z9K|G6*9IoL_3Eqm)sjXe(+Am_HVV#~PPRugC8lJI9;50tQ<7Gl@T$pdM&0WsE_JF>
zf+<mRBtDjq#C3_NqmqP7LY<bRCCa)HsH2jsOQt%wsIo4F>QIt(qfE(Kj;T%48E3jG
zS-GUEl8sANl&TXtO%gIgl_cb7Rg#cnP$J4CWTq-f$g!#<A;+OabV|q@R7pbGR7paP
zrxK`^kP}o%Lf)uK64H+G<s@%Y<GTrURFdr`s*-FsNtI-~94dhm4j%1%lxQAgX#tly
zRVf!G8lS9Nh!TxKmhz|sI%R1Q(E^;3*Nag{w8*;qQCFQ*q~>S|>Zl~?d_a{Xol8|o
z()nFgl308wp}#~4xj~gAWVtFy$O<kw6yyu4Bq4vGN)qx#E(H{1r7B6tjjALet5AA<
zM6H6{q)HO9T9qW^W|S&MOh}S+zNAVLvPP98WGzasCL54-sw5#_RwW7f3QE-}+Z4`v
zRg#c?Rg#bmC~0Xq$+GuGRg#cfR7pZMQE9}{1PQrSl_ca3RY^j=ic)n-mg@b_RY^kr
zg(^u%TIAET@mf+U)-*mmnYL2X0(dw1Nw_Jvn{oeog{B4Z51z|^8kV*<-Pgc-26zZ>
z8}0^PXn_ATY!av-sfB7`dV`AI{lHfYJa6OvBmAq!zY+fh*kr&~C$wo$XK{FI72Y+t
zKZ1Yv;~y!>$k?_GX>YHRJfpD*)ZK==4gW0oHwwodh+Zst4WFlL2EAs~5xw2t*R&4&
zYsbHIz!D9^VcSqgu<yjc>J0m&$z+DE23~^(f_)3Hui{>be}vbnV3QQAF~_m6YZPn-
z!*&8M>G-HT5bWo``(50#6zpgPD|Pp^VGX=vpoXNjk$j-Tx@fM=1}++#4fiDc>w7}e
zo<Rlau<PNaqh|)*O~u7E&)&GcS1SS%T;FSY^bYOOvd@PMo0T&{=VwzwBH1@{YT8K4
zsC0e4rfW|<=zi&u>h~vU^JUwgZT;c2oFDIgi{MQ<rXxH44^AJcHY4Y0IkL?cTRxel
zolTPcaUYo}S#$5X*LB~#Y=YM?TpPBC=&s>z!k<XL3P(-difMZB9>x)=3jiJ$(WL!&
zH`jqCC;+<R$7F?x&Kx`L2I_CdEz@584vi_mfYd(IXrF4dx28#+nB`@)$txX}mijN;
zjP?(b6CnH76;C9_QL^m~@mJiqnj?J^?faOYCPlkbm+i-ly&)kfIVDPaVwCo1d!qeK
zYM+{@C0vWPNd|4G=U%PpG4mar3k$}^ym>utY?(%Tv(bLKHeJ)EPp2Q;#?s?hy0Y<S
zY<4#N@C}dXZ^VcZ;Ni%TBh%B<GcqzVGc&<TyWNiHWAfz5)22<EF=NIZcifScmBsMc
zRxNvymVLX1#`t@Cwl*nSvjS0UMa<i4S4^6eeaocm+b3n;Jt;ez{@$HE>GteNw`9jx
z#Js(B#f%x*vu0$^nUQ_ZjO=Xsdr$U^IoUI2Wye><yuEgXrrA?8d%9*HtJ&@JcdT7Y
zw`(c(_==df*RDuUw`Zi=$EMqD>2^E)wb|3h+S4=a@f9&|uU(OuX&;wqw`JNVWZLcY
zcY;0BX3rdFkFSV%d+iEn&Lquh)~puIYNfvxs|K~01kD&*5%c!i74Wdq%vOupnr^nj
zc3aKqR<p%wPP4{W#Js(B#mJFX%Sh{}kyd@A)k=SL>&Q{okrr!wMa<i4SIE_Qo!@x*
zr!|13FcyNS(PGG+u8p0pWn)cDpPo&xsf0>iDg2H>#%g0B;A0`<SUl6mW>3!^I~_}h
z5TPX+p)p|uI&L}^pnxMFZi!~p256`?UZFq`ylnp1dgN6*eEsrB<Hz+!*YzJ+@Bi=d
zUt?M@1^=ZBs^*&4HBd{|{Fks}?yhrDAQ|lgkz8EasHxig_nSBW>b1?AtK^%ip_4;H
zEoX;@R9VwX2XR$qVVTLxnpGKFw7Fbo&z`l}T&mjUszT#v8Lt6CHWwHEZxXo9wonIj
z@k^Ijut3P>{Icb>U;XN}7F9nneZn0T?YJr!R&xnlE*m<K<?K7Now(NZcFOXmV)!7%
z#h$ZW0r|paJLx*>I;r5R1D(BngMGc7foiT!NKT(PZ*bnk^kiwTKr2w&stkfP>JAs~
z65XbgCr`e3BVAmsY%R(vZEY>hvb0u80RAPG$zlYb;-@T=g;(|T7~3J(Wf`=nT842J
z4Hh{iwEPVO0t!2qC*!}BH#u5w&C05*G`h!YOkQPHbo!!z{Dir2p?~QWK}19>DuO62
z9W3R4RIu49TlWPjlapU=tu#ikuhn967PY=i_3%bZOS3kd!hCJuBBrK@AB-Qs@@2!9
zKXf^57QSrJ5enCkOL3b)z#XG6F4GT4jyAx5_wcGK+9DyD=u`6z`Dtl6d9tNN37lrj
zssJurYJMtPC3vgCiE^?lIXT&wUW?sT+CB)9C(14dF&P6f^;tzIx8hRbFo^bY%o4tm
zs$%NtxeDzqO1^1mfQ*uFl#SssdEi=dWXPag5l^p*sE$S~>w({b(M1vB#p%<hPX!cx
zRubPqB1pmyKmsaB;s<2eCH7&2fqe$Q`bw!%h|)e;KPXnMsaR9AN+^D*a#2xlO#9QV
zt>PY8rk=Pv)gK8TUoKfck)<KJ-n-CMMFl$TlJ&hsd`0>rO@isfrSNxM96WtEIv(aV
z71eloe1t;Lr|M6fuC%a+&Gj@!)gS7MvMkAw_CqIMi=&rN^QG`JDI{KM1#|i2$st33
zaFvauP|}Nfz~WNlA8L7-Ca<|g>PF2amy6S>>NRMvby@a^zH-UsW3g~O&8EbAjbC7N
zIu%*5)fJY?$a>W}i;9Tb5P}FuWh(^0;GZ2ml>%I?Zvv`p#Ue23vr1PN@f<1sqJ9H`
zw^v$Ng#&--2EwoS3(?GChN|%;Cu`|g4!EG^(HQVj02I6gj`9m2T|>~xCr{!@UZ)7X
z!Ed~hQyd+StgnoSfI*+Jq)%-SQTgEZkN{(RR;P1-reuy?^@gCHFRAb7B~5u`{$-g2
zAOcU75P(Qo%1>3Y#aL49q)*j)O2<&w5rbGdS@F?g#wFWR9l_Yv$?}F%5xnYwSGa)=
z`j6H#ma`?9Ino|aKV&a%KG9f<lMlehmZ5Fp%2}mZab?ip0yn8U7turb;^YP58e1lO
zv1Q8OWYO@{`T*nN$^;)<-%3454MW`#Ik9C@i-V#Fb8qM?06l;2ja40|$_ZZ6=9RX$
z57LAl=AxvRW{A0^X-sdlEa{DwofYkI@<8=09>#h>dx9pVPb$9^qm`G$->Pbj{$Q6{
zFkdZ(1&l1Ot^uY`BViiCA0-b^UzMxGT8RGzu1~)aHRRFQY#k&a#DLiOqxsI_YMvgh
zk6kYWA4fmrD`tJ6)M_YP?$1?PIxp55kvpI%)-iz72_;k%FviF4$c6^^N&XDd@|TYg
z)mB;#hku%EnS@uWEDry8o&;gj#!gHG!JN{L(m9b55_+Y0Bg+{J<Np-?BL2_s%j5qr
zXRiL~i+j~)i<IZc>!P|FR1C(Ihr?e?j=&pm#+|7i99DlZS?LB%Q*e<o(*^u7qo>CR
zeTr`4BwwnmY>n|&BXNqoCK&|<5rJ3l<KZXSBJhg7yN&Vi{cdM=q$hgFcE;CVqW>s&
z%r&H48rD7n&rm~Ac!s+ag=hMP*Uy<V9Djs<)$34Pe{<$U=w*BuUkr7c7BgP;K6_aE
z2tG*<FIUAnz73zR2>&<;iup0<GhX!$yYyj~f{P<p+i<F*qvMpaR}@=yv_l0!vC{?L
z42zL2D$zymKV7l}0O+)+eZt!+pzC1m!XRvXp<x56!G=?EsH#{670wZyDl7F2HNh7Z
zTdBJqS)K@Yb{?UW`iWjv!Pr;HTKpy^qkN&t=+5peBK2P6v?~ZhzqT4Juvp|@^+JUg
zhD<2;Iikd%Au(W!QBJ>+H0tmxcKpytRZ({voj^(Aue?|vs^{p<Fy@grHseWW_pZCN
z)FsE$L98*R0zm6JoJDQ%;!`Ov1H&J^8_~aHrxE)r=Eev9abZ6cZcNaRm^MD-N3|RQ
z%U>kiCsLxpKGj7-eN8hW{R*a735nv2jPi{jU&i>Jvt0oKy(+**d><3u&l{X)ILnb(
zoSLb~-U#d?aXnRCGpaX2`Un<glPp0VsGW4oVzLMEq5QBw9%~GOsIF-Uv!@w__z-^Z
z`T;x}J|nopB8f=@#0Bm~-2QSTZ0D$5$VFkq?5q;t+ZGvg;12PpONHyW(-n!m<3n||
zl44qeFHWNv9jkhycorX@SGFELeX+}M4~*zsN~DU-l`pFzbLE&Bars0>uA*{PXT;={
zvW_EsjEPI69{69RglOCd#+gDzCQUA2i~(I0hJ!>&<?s+3*b#xt)*Ot)gx_(_ss`tc
zWA6c`CE}@bNyXhN?3Pis5d<4CcW<=aX(Qmq@M6MyBieQ`q!DY&71t$7ODjrCRbVFL
zY@>(Pp25Krgo@k6yL_y%DFw!LJcda4#LD-o*t&}$QAcr=nxm?!$62XL%BU;4<c!JZ
zQkBD^(uos;l~M~*$5})I<77htJQB-b>lP^QeM(-8NLtp#htWn9O?5OUjO?nPp=-s@
z>`hB!iddCnXGt}hQ{=41V8qSJ?8>OekWUpe%lSh)ib#jW%aUi1qby>R97D2-m184i
zWBwQ{0tuYmgC|a$hz#r$aY`5?<Y|gfO?C0nab+ak#j$aO&dSzxb~Og8jEkdTF-HxN
z(Nb?lN`xXHOkl){(F{gePSYD73#(Agh=gSzOk7}f%VRL2;B{PzSX(tdxyodLS5+kZ
zZCBA6(@AQLVoy0Diu_{c7Ld^rMRn0qB<3|ni-^|<cnM1sCqk*15@Cs{!*uYZ@!Uq@
zTrLr0w63*P4v1wwCc?!4A?`B1RXjs*zhMsiv*&s6Mr_NWt)vXhmh%o|Q7Mp=8Fi7E
zmd8hRF>{M{YQ~^NT3e+ukh(xssU9G-oCshoilAJkiBuTN4xy3e?Q3uE+uwe=y`7~s
z8o`o_Ndt^>o@Ok{7pjYnfl4uSLM9?Ik7q-L5ntkCR`$>$YXK{s;#Gr71WvYv?((8o
zm7lQE+dG^^r;xszr)jbz4*#7DQ(0Ci)2>>@hp5p2^^ZlT|B1-7&lbHRQKpJTF3P(>
zc1$TA@;cEdw~LQNBXOweVNl{`5{Ad1v6R`2_(>6Kc;2#kBo^aZ6$vS-6{OKl-RTyI
z!4xf#2odG@cr!lQjE^<rBh9;wxRiU3M3LM>B*tVK;_Kq$OVmj^jWH++<t<yjWr+B=
zGBP67E<UDI5vA;XSUlOMTF9H?AbH!-OF^g?@j+yK2&q6~QBwS9gpXKo1FfwCfj|x*
zBC(@_R*@r@t_mADYLxm~`r^@$QALd0E<Ri&^@3iMuffU&;gAd!jYyF-CbdOeXn17t
zL86Kgop$a)>I^6`S%MVHzg&z94&y^ZC?DuTBQU&HTo?(8vHW90Lg*j-<%_kAd^CQg
zf;38WN{KHc5|n{pM_e3uRTTJt3IQqZ!=`T)MSR#nsiIJiws?&oFRL<(UQ}A;3#dax
z8lc43yEVc%BY@LW^o>xq6)raORW^>-5Uz2g=IIK&_Bi52*W<5McT#XxttF&WSe77n
zTd~<n?g92#HAG>wxvI@8CdTlFfmT%o-eFf3U_&a}V#CjSv_^mx39X=<Ne>x&qG-Uo
z%!p4T$`{qniV9Nfh>@fhLK~crR?S%%sIc@oVaeKUPSHyFV{B$_(2Q&brW~mS8*Q>7
z5GaD+s=Z3~et?)R89)ul0+%(87O({=qnk?2xeoD%b3m(Tw`3Ky%RB9l$j!xx+CZSs
zLS;lQu!a@dKs%%j6eC+hf9YOnp_D&GG0}fTpeaD~X&So6UlLHF6aBzcl6!;TBT#|y
zx3>?#85!V!V*t|$z9GfJQ3hg+LE6+?H7M`cDx><tVjdY(G=nQd<U1=giXey{#18O$
zyEKX#C}vRc0-0IbjN=?Uty=1j_Fd3@`>6^$m#JMvd*?bkjq^Q;7uC21qyevRl8bR-
zu!md?=_{fVBve4-Y_Z*e{wmNfoNtW=Z^2f61uMpi;lBJ(bpMN-hz+#6R4K$M@T;Od
zfd1j7V=s*SoQn1V@F}a5HnVzBhD%;)>Feapt1fVI9gp9lNd|P%CRJ${za_fhcTvEE
zdmjyi@e!XiazZKzA>*5fGB%qCKMS5_byhl^vuXaQ8PS0o#t(r!F~}Y>7{I<V-h&=Y
z@?Sew4`_C$v(pKEhGFwRD&SQ_&8S@wIZB(QLSw(TO0%nRR<*d2=ZS2*Ccac@o$8LU
za2fmvU}a<hPE-}S2#)y!IKH<lepI$*fdm)YOa72Q2z^Z=3cz;sH&9ejL`!3nWmEem
z+HJvR%VAXFFY(8?6JnI*Zb}ul0f`Z~6Wthh3ndY;pr!j>fiYJF0@&t&TiII#pAu~c
zXrB(;?{7WQdH_x&Lf?*c7%z_}OVP&+pnmNNe;-d6mQH*3z^V3#YiKxySVKi5C%9nq
z=%x)=EZFjEZ9jddXxDK+dH32QiE<ijnueF+PC(&TKn!lKmw$|1hm++ed*~mFtNQ8V
zyL8IPNw|oA)DdkWP%5A5@iuN#0JW+toic#VAvI_NbRRXwCGpzW`JyhAGiA6ZHgXgQ
zj^1-U{opOVCw$VSGMp*HjWQf4!*!BQ6Ja4dbLL1#iF%V|!#R>}5%)*Pab<JAh7%<F
zrFz5hA(sbuBF>I6E}~C)Dbxj@F)}<F!<V6Ys>8ZF)keNcMSEX+A7*f%9f~gi_DOp>
z&|c&ueJqpO>kP*vfM&!DZGaSKg>!(#8v2Yp5b{6lP8;+_1+`<RBiTatq5$ddKv5P6
zGhL7t{)6=Z;lv}<6}0mJg*DLH16rIH0r!D{NWUwWA;w*hlZ75>(#SdJMvl0GhJo@r
zAS7xK+~DE|{u%1T8E8#QNid&<)XGcpM!f3IUGnhP6L79lx*Um1a5h@2HlY4={}TuP
z#DPC?;7=U*69@jpf&VTJtS>2@F>B`CGw+(=oZ%_CYu4<ntl}B?jC!_n?kwk1v+i`x
snSJMs=btVuD_i^g%r$GDE1CK1`jr(Wr8C#A_h?!|(tj5n|3C5kZ_EYp(EtDd

literal 0
HcmV?d00001

-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 44+ messages in thread

* [Qemu-devel] [RfC PATCH 14/15] virtio-gpu: add to display-vga test
  2015-02-23 10:23 [Qemu-devel] [RfC PATCH 00/15] virtio-gpu: Gerd Hoffmann
                   ` (12 preceding siblings ...)
  2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 13/15] virtio-vga: add vgabios binary Gerd Hoffmann
@ 2015-02-23 10:23 ` Gerd Hoffmann
  2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 15/15] [hack] virtio-gpu: maskerade as -device VGA Gerd Hoffmann
  2015-02-26 18:40 ` [Qemu-devel] [RfC PATCH 00/15] virtio-gpu: Max Reitz
  15 siblings, 0 replies; 44+ messages in thread
From: Gerd Hoffmann @ 2015-02-23 10:23 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 tests/Makefile           |  3 +++
 tests/display-vga-test.c | 18 ++++++++++++++++++
 2 files changed, 21 insertions(+)

diff --git a/tests/Makefile b/tests/Makefile
index d5df168..8c169b2 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -131,6 +131,9 @@ check-qtest-pci-y += tests/display-vga-test$(EXESUF)
 gcov-files-pci-y += hw/display/vga.c
 gcov-files-pci-y += hw/display/cirrus_vga.c
 gcov-files-pci-y += hw/display/vga-pci.c
+gcov-files-pci-y += hw/display/virtio-gpu.c
+gcov-files-pci-y += hw/display/virtio-gpu-pci.c
+gcov-files-pci-y += hw/display/virtio-vga.c
 check-qtest-pci-y += tests/intel-hda-test$(EXESUF)
 gcov-files-pci-y += hw/audio/intel-hda.c hw/audio/hda-codec.c
 
diff --git a/tests/display-vga-test.c b/tests/display-vga-test.c
index 17f5910..cd0b873 100644
--- a/tests/display-vga-test.c
+++ b/tests/display-vga-test.c
@@ -36,6 +36,20 @@ static void pci_multihead(void)
     qtest_end();
 }
 
+#ifdef CONFIG_VIRTIO_GPU
+static void pci_virtio_gpu(void)
+{
+    qtest_start("-vga none -device virtio-gpu-pci");
+    qtest_end();
+}
+
+static void pci_virtio_vga(void)
+{
+    qtest_start("-vga none -device virtio-vga");
+    qtest_end();
+}
+#endif
+
 int main(int argc, char **argv)
 {
     int ret;
@@ -46,6 +60,10 @@ int main(int argc, char **argv)
     qtest_add_func("/display/pci/stdvga", pci_stdvga);
     qtest_add_func("/display/pci/secondary", pci_secondary);
     qtest_add_func("/display/pci/multihead", pci_multihead);
+#ifdef CONFIG_VIRTIO_GPU
+    qtest_add_func("/display/pci/virtio-gpu", pci_virtio_gpu);
+    qtest_add_func("/display/pci/virtio-vga", pci_virtio_vga);
+#endif
     ret = g_test_run();
 
     return ret;
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [Qemu-devel] [RfC PATCH 15/15] [hack] virtio-gpu: maskerade as -device VGA
  2015-02-23 10:23 [Qemu-devel] [RfC PATCH 00/15] virtio-gpu: Gerd Hoffmann
                   ` (13 preceding siblings ...)
  2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 14/15] virtio-gpu: add to display-vga test Gerd Hoffmann
@ 2015-02-23 10:23 ` Gerd Hoffmann
  2015-02-26 18:40 ` [Qemu-devel] [RfC PATCH 00/15] virtio-gpu: Max Reitz
  15 siblings, 0 replies; 44+ messages in thread
From: Gerd Hoffmann @ 2015-02-23 10:23 UTC (permalink / raw)
  To: qemu-devel; +Cc: Gerd Hoffmann, Anthony Liguori, Michael S. Tsirkin

Newer libvirt versions start looking up VGA in the QOM tree.
So tricking libvirt this way ...

    <qemu:arg value='-set'/>
    <qemu:arg value='device.video0.driver=virtio-vga'/>

... to test virtio-vga stopped working.

Lets rename VGA to stdvga and virtio-vga to VGA to get things going
again.  A simple ...

      <model type='vga' vram='16384' heads='1'/>

... will give you virtio-vga when building qemu with this patch applied.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 hw/display/vga-pci.c    | 2 +-
 hw/display/virtio-vga.c | 4 +++-
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/hw/display/vga-pci.c b/hw/display/vga-pci.c
index 53739e4..6a1b32d 100644
--- a/hw/display/vga-pci.c
+++ b/hw/display/vga-pci.c
@@ -325,7 +325,7 @@ static void secondary_class_init(ObjectClass *klass, void *data)
 }
 
 static const TypeInfo vga_info = {
-    .name          = "VGA",
+    .name          = "stdvga",
     .parent        = TYPE_PCI_DEVICE,
     .instance_size = sizeof(PCIVGAState),
     .class_init    = vga_class_init,
diff --git a/hw/display/virtio-vga.c b/hw/display/virtio-vga.c
index 0e48ba9..57e25db 100644
--- a/hw/display/virtio-vga.c
+++ b/hw/display/virtio-vga.c
@@ -7,7 +7,7 @@
 /*
  * virtio-vga: This extends VirtioPCIProxy.
  */
-#define TYPE_VIRTIO_VGA "virtio-vga"
+#define TYPE_VIRTIO_VGA "VGA"
 #define VIRTIO_VGA(obj) \
         OBJECT_CHECK(VirtIOVGA, (obj), TYPE_VIRTIO_VGA)
 
@@ -15,6 +15,7 @@ typedef struct VirtIOVGA {
     VirtIOPCIProxy parent_obj;
     VirtIOGPU      vdev;
     VGACommonState vga;
+    uint32_t       dummy;
 } VirtIOVGA;
 
 static void virtio_vga_invalidate_display(void *opaque)
@@ -114,6 +115,7 @@ static void virtio_vga_reset(DeviceState *dev)
 static Property virtio_vga_properties[] = {
     DEFINE_VIRTIO_GPU_PROPERTIES(VirtIOVGA, vdev.conf),
     DEFINE_VIRTIO_GPU_PCI_PROPERTIES(VirtIOPCIProxy),
+    DEFINE_PROP_UINT32("vgamem_mb", VirtIOVGA, dummy, 16),
     DEFINE_PROP_END_OF_LIST(),
 };
 
-- 
1.8.3.1

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* Re: [Qemu-devel] [RfC PATCH 11/15] virtio-vga: add '-vga virtio' support
  2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 11/15] virtio-vga: add '-vga virtio' support Gerd Hoffmann
@ 2015-02-24 16:26   ` Marc-André Lureau
  2015-02-27  9:27     ` Gerd Hoffmann
  0 siblings, 1 reply; 44+ messages in thread
From: Marc-André Lureau @ 2015-02-24 16:26 UTC (permalink / raw)
  To: Gerd Hoffmann
  Cc: Dave Airlie, Michael S. Tsirkin, qemu-devel, Anthony Liguori,
	Paolo Bonzini

Hi Gerd

I think it's missing qemu-options:

diff --git a/qemu-options.hx b/qemu-options.hx
index 85ca3ad..9315672 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1077,7 +1077,7 @@ Rotate graphical output some deg left (only PXA LCD).
 ETEXI

 DEF("vga", HAS_ARG, QEMU_OPTION_vga,
-    "-vga [std|cirrus|vmware|qxl|xenfb|tcx|cg3|none]\n"
+    "-vga [std|cirrus|vmware|qxl|xenfb|tcx|cg3|virtio|none]\n"
     "                select video card type\n", QEMU_ARCH_ALL)
 STEXI
 @item -vga @var{type}
@@ -1110,6 +1110,8 @@ fixed resolution of 1024x768.
 (sun4m only) Sun cgthree framebuffer. This is a simple 8-bit framebuffer
 for sun4m machines available in both 1024x768 (OpenBIOS) and 1152x900 (OBP)
 resolutions aimed at people wishing to run older Solaris versions.
+@item virtio
+Virtio VGA
 @item none
 Disable VGA card.
 @end table

On Mon, Feb 23, 2015 at 11:23 AM, Gerd Hoffmann <kraxel@redhat.com> wrote:
> Some convinience fluff:  Add support for '-vga virtio', also add
> virtio-vga to the list of vga cards so '-device virtio-vga' will
> turn off the default vga.
>
> Written by Dave Airlie and Gerd Hoffmann.
>
> Signed-off-by: Dave Airlie <airlied@redhat.com>
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
>  hw/pci/pci.c            |  2 ++
>  include/sysemu/sysemu.h |  2 +-
>  vl.c                    | 13 +++++++++++++
>  3 files changed, 16 insertions(+), 1 deletion(-)
>
> diff --git a/hw/pci/pci.c b/hw/pci/pci.c
> index d508930..3a2b8ad 100644
> --- a/hw/pci/pci.c
> +++ b/hw/pci/pci.c
> @@ -1662,6 +1662,8 @@ PCIDevice *pci_vga_init(PCIBus *bus)
>          return pci_create_simple(bus, -1, "VGA");
>      case VGA_VMWARE:
>          return pci_create_simple(bus, -1, "vmware-svga");
> +    case VGA_VIRTIO:
> +        return pci_create_simple(bus, -1, "virtio-vga");
>      case VGA_NONE:
>      default: /* Other non-PCI types. Checking for unsupported types is already
>                  done in vl.c. */
> diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
> index 748d059..1c0e2a6 100644
> --- a/include/sysemu/sysemu.h
> +++ b/include/sysemu/sysemu.h
> @@ -107,7 +107,7 @@ extern int autostart;
>
>  typedef enum {
>      VGA_NONE, VGA_STD, VGA_CIRRUS, VGA_VMWARE, VGA_XENFB, VGA_QXL,
> -    VGA_TCX, VGA_CG3, VGA_DEVICE
> +    VGA_TCX, VGA_CG3, VGA_DEVICE, VGA_VIRTIO,
>  } VGAInterfaceType;
>
>  extern int vga_interface_type;
> diff --git a/vl.c b/vl.c
> index 8c8f142..27fe972 100644
> --- a/vl.c
> +++ b/vl.c
> @@ -234,6 +234,7 @@ static struct {
>      { .driver = "isa-cirrus-vga",       .flag = &default_vga       },
>      { .driver = "vmware-svga",          .flag = &default_vga       },
>      { .driver = "qxl-vga",              .flag = &default_vga       },
> +    { .driver = "virtio-vga",           .flag = &default_vga       },
>  };
>
>  static QemuOptsList qemu_rtc_opts = {
> @@ -1870,6 +1871,11 @@ static bool cg3_vga_available(void)
>      return object_class_by_name("cgthree");
>  }
>
> +static bool virtio_vga_available(void)
> +{
> +    return object_class_by_name("virtio-vga");
> +}
> +
>  static void select_vgahw (const char *p)
>  {
>      const char *opts;
> @@ -1896,6 +1902,13 @@ static void select_vgahw (const char *p)
>              fprintf(stderr, "Error: VMWare SVGA not available\n");
>              exit(0);
>          }
> +    } else if (strstart(p, "virtio", &opts)) {
> +        if (virtio_vga_available()) {
> +            vga_interface_type = VGA_VIRTIO;
> +        } else {
> +            fprintf(stderr, "Error: Virtio VGA not available\n");
> +            exit(0);
> +        }
>      } else if (strstart(p, "xenfb", &opts)) {
>          vga_interface_type = VGA_XENFB;
>      } else if (strstart(p, "qxl", &opts)) {
> --
> 1.8.3.1
>
>



-- 
Marc-André Lureau

^ permalink raw reply related	[flat|nested] 44+ messages in thread

* Re: [Qemu-devel] [RfC PATCH 05/15] virtio-gpu/2d: add hardware spec include file
  2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 05/15] virtio-gpu/2d: add hardware spec include file Gerd Hoffmann
@ 2015-02-25 20:04   ` Max Reitz
  2015-02-27  9:37     ` Gerd Hoffmann
  0 siblings, 1 reply; 44+ messages in thread
From: Max Reitz @ 2015-02-25 20:04 UTC (permalink / raw)
  To: Gerd Hoffmann, qemu-devel; +Cc: Dave Airlie

On 2015-02-23 at 05:23, Gerd Hoffmann wrote:
> This patch adds the header file with structs and defines for
> the virtio based gpu device.  Covers 2d operations only.
>
> Written by Dave Airlie and Gerd Hoffmann.
>
> Signed-off-by: Dave Airlie <airlied@redhat.com>
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
>   include/hw/virtio/virtgpu_hw.h | 203 +++++++++++++++++++++++++++++++++++++++++
>   1 file changed, 203 insertions(+)
>   create mode 100644 include/hw/virtio/virtgpu_hw.h
>
> diff --git a/include/hw/virtio/virtgpu_hw.h b/include/hw/virtio/virtgpu_hw.h
> new file mode 100644
> index 0000000..d6641e8
> --- /dev/null
> +++ b/include/hw/virtio/virtgpu_hw.h
> @@ -0,0 +1,203 @@
> +/*
> + * Virtio GPU Device
> + *
> + * Copyright Red Hat, Inc. 2013-2014

Hm... Well, if there haven't been any changes since 2014...

> + *
> + * Authors:
> + *     Dave Airlie <airlied@redhat.com>
> + *     Gerd Hoffmann <kraxel@redhat.com>
> + *
> + * This header is BSD licensed so anyone can use the definitions
> + * to implement compatible drivers/servers:
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions
> + * are met:
> + * 1. Redistributions of source code must retain the above copyright
> + *    notice, this list of conditions and the following disclaimer.
> + * 2. Redistributions in binary form must reproduce the above copyright
> + *    notice, this list of conditions and the following disclaimer in the
> + *    documentation and/or other materials provided with the distribution.
> + * 3. Neither the name of IBM nor the names of its contributors

Is the "IBM" intended?

> + *    may be used to endorse or promote products derived from this software
> + *    without specific prior written permission.
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
> + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
> + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL IBM OR
> + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
> + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
> + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
> + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
> + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
> + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
> + * SUCH DAMAGE.
> + */
> +
> +#ifndef VIRTIO_GPU_HW_H
> +#define VIRTIO_GPU_HW_H
> +
> +enum virtio_gpu_ctrl_type {
> +    VIRTIO_GPU_UNDEFINED = 0,
> +
> +    /* 2d commands */
> +    VIRTIO_GPU_CMD_GET_DISPLAY_INFO = 0x0100,
> +    VIRTIO_GPU_CMD_RESOURCE_CREATE_2D,
> +    VIRTIO_GPU_CMD_RESOURCE_UNREF,
> +    VIRTIO_GPU_CMD_SET_SCANOUT,
> +    VIRTIO_GPU_CMD_RESOURCE_FLUSH,
> +    VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D,
> +    VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING,
> +    VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING,
> +
> +    /* cursor commands */
> +    VIRTIO_GPU_CMD_UPDATE_CURSOR = 0x0300,
> +    VIRTIO_GPU_CMD_MOVE_CURSOR,
> +
> +    /* success responses */
> +    VIRTIO_GPU_RESP_OK_NODATA = 0x1100,
> +    VIRTIO_GPU_RESP_OK_DISPLAY_INFO,
> +
> +    /* error responses */
> +    VIRTIO_GPU_RESP_ERR_UNSPEC = 0x1200,
> +    VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY,
> +    VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID,
> +    VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID,
> +    VIRTIO_GPU_RESP_ERR_INVALID_CONTEXT_ID,
> +    VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER,
> +};
> +
> +#define VIRTIO_GPU_FLAG_FENCE (1 << 0)
> +
> +struct virtio_gpu_ctrl_hdr {
> +    uint32_t type;
> +    uint32_t flags;
> +    uint64_t fence_id;
> +    uint32_t ctx_id;
> +    uint32_t padding;
> +};

Shouldn't all these structures be QEMU_PACKED? In practice, it won't 
matter (I hope!), but if you're relying on it...

Usage of QEMU_PACKED doesn't seem to widespread in include/hw/virtio, so 
maybe it's fine the way it is.

(sorry I don't have any really useful comments, I'm less reviewing and 
more just reading into this series (because I don't have the knowledge 
to really review most of its patches))

Max

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [Qemu-devel] [RfC PATCH 06/15] virtio-gpu/2d: add virtio gpu core code
  2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 06/15] virtio-gpu/2d: add virtio gpu core code Gerd Hoffmann
@ 2015-02-26 16:08   ` Max Reitz
  2015-02-27 11:10     ` Gerd Hoffmann
  2015-03-01 22:03     ` Dave Airlie
  0 siblings, 2 replies; 44+ messages in thread
From: Max Reitz @ 2015-02-26 16:08 UTC (permalink / raw)
  To: Gerd Hoffmann, qemu-devel
  Cc: Dave Airlie, Anthony Liguori, Michael S. Tsirkin

On 2015-02-23 at 05:23, Gerd Hoffmann wrote:
> This patch adds the core code for virtio gpu emulation,
> covering 2d support.
>
> Written by Dave Airlie and Gerd Hoffmann.
>
> Signed-off-by: Dave Airlie<airlied@redhat.com>
> Signed-off-by: Gerd Hoffmann<kraxel@redhat.com>
> ---
>   hw/display/Makefile.objs       |   2 +
>   hw/display/virtio-gpu.c        | 903 +++++++++++++++++++++++++++++++++++++++++
>   include/hw/virtio/virtio-gpu.h | 147 +++++++
>   trace-events                   |  14 +
>   4 files changed, 1066 insertions(+)
>   create mode 100644 hw/display/virtio-gpu.c
>   create mode 100644 include/hw/virtio/virtio-gpu.h

Again I mostly only have formal complaints...

But one non-formal question: As far as I understood virtio-gpu's mode of 
operation from this patch, it looks like there is one resource per 
scanout, and that resource is basically the whole screen (which can be 
updated partially).

If that is the case, what do we gain from being able to display a 
resource on multiple scanouts? If we don't associate a scanout to a 
resource with set_scanout, the resource won't ever be displayed on that 
scanout; and if we associate it, the scanout's position and dimension 
will be exactly the same as the resource's, so associating a resource 
with multiple scanouts means that all those scanouts will be duplicates 
of each other, which in turn means we can duplicate heads. But that 
seems more like a frontend feature to me...

> diff --git a/hw/display/Makefile.objs b/hw/display/Makefile.objs
> index 7ed76a9..6990634 100644
> --- a/hw/display/Makefile.objs
> +++ b/hw/display/Makefile.objs
> @@ -33,3 +33,5 @@ obj-$(CONFIG_CG3) += cg3.o
>   obj-$(CONFIG_VGA) += vga.o
>   
>   common-obj-$(CONFIG_QXL) += qxl.o qxl-logger.o qxl-render.o
> +
> +obj-$(CONFIG_VIRTIO) += virtio-gpu.o
> diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
> new file mode 100644
> index 0000000..514f71f
> --- /dev/null
> +++ b/hw/display/virtio-gpu.c
> @@ -0,0 +1,903 @@
> +/*
> + * Virtio GPU Device
> + *
> + * Copyright Red Hat, Inc. 2013-2014
> + *
> + * Authors:
> + *     Dave Airlie<airlied@redhat.com>
> + *     Gerd Hoffmann<kraxel@redhat.com>
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2.
> + * See the COPYING file in the top-level directory.
> + */
> +
> +#include "qemu-common.h"
> +#include "qemu/iov.h"
> +#include "ui/console.h"
> +#include "trace.h"
> +#include "hw/virtio/virtio.h"
> +#include "hw/virtio/virtio-gpu.h"
> +#include "hw/virtio/virtio-bus.h"
> +
> +static struct virtio_gpu_simple_resource*
> +virtio_gpu_find_resource(VirtIOGPU *g, uint32_t resource_id);
> +
> +static void update_cursor_data_simple(VirtIOGPU *g,
> +                                      struct virtio_gpu_scanout *s,
> +                                      uint32_t resource_id)
> +{
> +    struct virtio_gpu_simple_resource *res;
> +    uint32_t pixels;
> +
> +    res = virtio_gpu_find_resource(g, resource_id);
> +    if (!res) {
> +        return;
> +    }
> +
> +    pixels = s->current_cursor->width * s->current_cursor->height;

This multiplication might overflow (but I can't imagine that one could 
use this for an exploit).

> +    memcpy(s->current_cursor->data,
> +           pixman_image_get_data(res->image),
> +           pixels * sizeof(uint32_t));
> +}
> +
> +static void update_cursor(VirtIOGPU *g, struct virtio_gpu_update_cursor *cursor)
> +{
> +    struct virtio_gpu_scanout *s;
> +
> +    if (cursor->pos.scanout_id >= g->conf.max_outputs) {
> +        return;
> +    }
> +    s = &g->scanout[cursor->pos.scanout_id];
> +
> +    if (cursor->hdr.type != VIRTIO_GPU_CMD_MOVE_CURSOR) {
> +        if (!s->current_cursor) {
> +            s->current_cursor = cursor_alloc(64, 64);
> +        }
> +
> +        s->current_cursor->hot_x = cursor->hot_x;
> +        s->current_cursor->hot_y = cursor->hot_y;
> +
> +        if (cursor->resource_id > 0) {
> +            update_cursor_data_simple(g, s, cursor->resource_id);
> +        }
> +        dpy_cursor_define(s->con, s->current_cursor);
> +    }
> +    dpy_mouse_set(s->con, cursor->pos.x, cursor->pos.y,
> +                  cursor->resource_id ? 1 : 0);
> +}
> +
> +static void virtio_gpu_get_config(VirtIODevice *vdev, uint8_t *config)
> +{
> +    VirtIOGPU *g = VIRTIO_GPU(vdev);
> +    memcpy(config, &g->virtio_config, sizeof(g->virtio_config));
> +}
> +
> +static void virtio_gpu_set_config(VirtIODevice *vdev, const uint8_t *config)
> +{
> +    VirtIOGPU *g = VIRTIO_GPU(vdev);
> +    struct virtio_gpu_config vgconfig;
> +
> +    memcpy(&vgconfig, config, sizeof(g->virtio_config));
> +
> +    if (vgconfig.events_clear) {
> +        g->virtio_config.events_read &= ~vgconfig.events_clear;
> +    }
> +}
> +
> +static uint64_t virtio_gpu_get_features(VirtIODevice *vdev, uint64_t features)
> +{
> +    return features;
> +}
> +
> +static void virtio_gpu_set_features(VirtIODevice *vdev, uint64_t features)
> +{
> +}
> +
> +static void virtio_gpu_notify_event(VirtIOGPU *g, uint32_t event_type)
> +{
> +    g->virtio_config.events_read |= event_type;
> +    virtio_notify_config(&g->parent_obj);
> +}
> +
> +static struct virtio_gpu_simple_resource *
> +virtio_gpu_find_resource(VirtIOGPU *g, uint32_t resource_id)
> +{
> +    struct virtio_gpu_simple_resource *res;
> +
> +    QTAILQ_FOREACH(res, &g->reslist, next) {
> +        if (res->resource_id == resource_id) {
> +            return res;
> +        }
> +    }
> +    return NULL;
> +}

How often do you think this function is called, and how many resources 
do you expect there to be? Would it make sense to make this a hash table?

(Anyway, this would be an optimization which can be implemented in the 
future)

(Update after review: There seems to be one resource per scanout, so 
this simple loop should be just fine (if the guest does not try a DoS 
attack and creates an enormous amount of resources...))

> +
> +void virtio_gpu_ctrl_response(VirtIOGPU *g,
> +                              struct virtio_gpu_ctrl_command *cmd,
> +                              struct virtio_gpu_ctrl_hdr *resp,
> +                              size_t resp_len)
> +{
> +    size_t s;
> +
> +    if (cmd->cmd_hdr.flags & VIRTIO_GPU_FLAG_FENCE) {
> +        resp->flags |= VIRTIO_GPU_FLAG_FENCE;
> +        resp->fence_id = cmd->cmd_hdr.fence_id;
> +        resp->ctx_id = cmd->cmd_hdr.ctx_id;
> +    }
> +    s = iov_from_buf(cmd->elem.in_sg, cmd->elem.in_num, 0, resp, resp_len);
> +    if (s != resp_len) {
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: response size incorrect %zu vs %zu\n",
> +                      __func__, s, resp_len);
> +    }
> +    virtqueue_push(cmd->vq, &cmd->elem, s);
> +    virtio_notify(VIRTIO_DEVICE(g), cmd->vq);
> +    cmd->finished = true;
> +}
> +
> +void virtio_gpu_ctrl_response_nodata(VirtIOGPU *g,
> +                                     struct virtio_gpu_ctrl_command *cmd,
> +                                     enum virtio_gpu_ctrl_type type)
> +{
> +    struct virtio_gpu_ctrl_hdr resp;
> +
> +    memset(&resp, 0, sizeof(resp));
> +    resp.type = type;
> +    virtio_gpu_ctrl_response(g, cmd, &resp, sizeof(resp));
> +}
> +
> +static void
> +virtio_gpu_fill_display_info(VirtIOGPU *g,
> +                             struct virtio_gpu_resp_display_info *dpy_info)
> +{
> +    int i;
> +
> +    for (i = 0; i < g->conf.max_outputs; i++) {
> +        if (g->enabled_output_bitmask & (1 << i)) {
> +            dpy_info->pmodes[i].enabled = 1;
> +            dpy_info->pmodes[i].r.width = g->req_state[i].width;
> +            dpy_info->pmodes[i].r.height = g->req_state[i].height;
> +        }
> +    }
> +}
> +
> +void virtio_gpu_get_display_info(VirtIOGPU *g,
> +                                 struct virtio_gpu_ctrl_command *cmd)
> +{
> +    struct virtio_gpu_resp_display_info display_info;
> +
> +    trace_virtio_gpu_cmd_get_display_info();
> +    memset(&display_info, 0, sizeof(display_info));
> +    display_info.hdr.type = VIRTIO_GPU_RESP_OK_DISPLAY_INFO;
> +    virtio_gpu_fill_display_info(g, &display_info);
> +    virtio_gpu_ctrl_response(g, cmd, &display_info.hdr,
> +                             sizeof(display_info));
> +}
> +
> +static pixman_format_code_t get_pixman_format(uint32_t virtio_gpu_format)
> +{
> +    switch (virtio_gpu_format) {
> +#ifdef HOST_WORDS_BIGENDIAN
> +    case VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM:
> +        return PIXMAN_b8g8r8x8;
> +    case VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM:
> +        return PIXMAN_b8g8r8a8;
> +    case VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM:
> +        return PIXMAN_x8r8g8b8;
> +    case VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM:
> +        return PIXMAN_a8r8g8b8;
> +    case VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM:
> +        return PIXMAN_r8g8b8x8;
> +    case VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM:
> +        return PIXMAN_r8g8b8a8;
> +    case VIRTIO_GPU_FORMAT_X8B8G8R8_UNORM:
> +        return PIXMAN_x8b8g8r8;
> +    case VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM:
> +        return PIXMAN_a8b8g8r8;
> +#else
> +    case VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM:
> +        return PIXMAN_x8r8g8b8;
> +    case VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM:
> +        return PIXMAN_a8r8g8b8;
> +    case VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM:
> +        return PIXMAN_b8g8r8x8;
> +    case VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM:
> +        return PIXMAN_b8g8r8a8;
> +    case VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM:
> +        return PIXMAN_x8b8g8r8;
> +    case VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM:
> +        return PIXMAN_a8b8g8r8;
> +    case VIRTIO_GPU_FORMAT_X8B8G8R8_UNORM:
> +        return PIXMAN_r8g8b8x8;
> +    case VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM:
> +        return PIXMAN_r8g8b8a8;
> +#endif
> +    default:
> +        return 0;
> +    }
> +}
> +
> +static void virtio_gpu_resource_create_2d(VirtIOGPU *g,
> +                                          struct virtio_gpu_ctrl_command *cmd)
> +{
> +    pixman_format_code_t pformat;
> +    struct virtio_gpu_simple_resource *res;
> +    struct virtio_gpu_resource_create_2d c2d;
> +
> +    VIRTIO_GPU_FILL_CMD(c2d);
> +    trace_virtio_gpu_cmd_res_create_2d(c2d.resource_id, c2d.format,
> +                                       c2d.width, c2d.height);
> +
> +    res = virtio_gpu_find_resource(g, c2d.resource_id);
> +    if (res) {
> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: resource already exists %d\n",
> +                      __func__, c2d.resource_id);

Doesn't make a difference as long as sizeof(int) == sizeof(int32_t), but 
%" PRId32 " would be nicer than just %d (the same applies to other 
places, too).

> +        cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
> +        return;
> +    }
> +
> +    res = g_new0(struct virtio_gpu_simple_resource, 1);
> +
> +    res->width = c2d.width;
> +    res->height = c2d.height;
> +    res->format = c2d.format;
> +    res->resource_id = c2d.resource_id;

Considering resource_id == 0 is sometimes (apparently) used as "no 
resource" (e.g. in transfer_to_host_2d), would it make sense to test 
against that here?

> +
> +    pformat = get_pixman_format(c2d.format);
> +    if (!pformat) {
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: host couldn't handle guest format %d\n",
> +                      __func__, c2d.format);
> +        cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
> +        return;
> +    }
> +    res->image = pixman_image_create_bits(pformat,
> +                                          c2d.width,
> +                                          c2d.height,
> +                                          NULL, 0);
> +
> +    if (!res->image) {
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: resource creation failed %d %d %d\n",
> +                      __func__, c2d.resource_id, c2d.width, c2d.height);
> +        g_free(res);
> +        cmd->error = VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY;
> +        return;
> +    }
> +
> +    QTAILQ_INSERT_HEAD(&g->reslist, res, next);
> +}
> +
> +static void virtio_gpu_resource_destroy(VirtIOGPU *g,
> +                                        struct virtio_gpu_simple_resource *res)
> +{
> +    pixman_image_unref(res->image);
> +    QTAILQ_REMOVE(&g->reslist, res, next);
> +    g_free(res);
> +}
> +
> +static void virtio_gpu_resource_unref(VirtIOGPU *g,
> +                                      struct virtio_gpu_ctrl_command *cmd)
> +{
> +    struct virtio_gpu_simple_resource *res;
> +    struct virtio_gpu_resource_unref unref;
> +
> +    VIRTIO_GPU_FILL_CMD(unref);
> +    trace_virtio_gpu_cmd_res_unref(unref.resource_id);
> +
> +    res = virtio_gpu_find_resource(g, unref.resource_id);
> +    if (!res) {
> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal resource specified %d\n",
> +                      __func__, unref.resource_id);
> +        cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
> +        return;
> +    }
> +    virtio_gpu_resource_destroy(g, res);
> +}
> +
> +static void virtio_gpu_transfer_to_host_2d(VirtIOGPU *g,
> +                                           struct virtio_gpu_ctrl_command *cmd)
> +{
> +    struct virtio_gpu_simple_resource *res;
> +    int h;
> +    uint32_t src_offset, dst_offset, stride;
> +    int bpp;
> +    pixman_format_code_t format;
> +    struct virtio_gpu_transfer_to_host_2d t2d;
> +
> +    VIRTIO_GPU_FILL_CMD(t2d);
> +    trace_virtio_gpu_cmd_res_xfer_toh_2d(t2d.resource_id);
> +
> +    res = virtio_gpu_find_resource(g, t2d.resource_id);
> +    if (!res || !res->iov) {
> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal resource specified %d\n",
> +                      __func__, t2d.resource_id);
> +        cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
> +        return;
> +    }
> +
> +    if (t2d.r.x > res->width ||
> +        t2d.r.y > res->height ||
> +        t2d.r.width > res->width ||
> +        t2d.r.height > res->height ||
> +        t2d.r.x + t2d.r.width > res->width ||
> +        t2d.r.y + t2d.r.height > res->height) {
> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: transfer bounds outside resource"
> +                      " bounds for resource %d: %d %d %d %d vs %d %d\n",
> +                      __func__, t2d.resource_id, t2d.r.x, t2d.r.y,
> +                      t2d.r.width, t2d.r.height, res->width, res->height);
> +        cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
> +        return;
> +    }
> +
> +    format = pixman_image_get_format(res->image);
> +    bpp = (PIXMAN_FORMAT_BPP(format) + 7) / 8;

Could have used DIV_ROUND_UP(); also, I don't find it anywhere in the 
virtio-gpu spec (at least not in the one spec I found), so will this 
really work if PIXMAN_FORMAT_BPP(format) is not a multiple of 8? I can 
imagine this being correct for *_BPP() == 15, but maybe not so much for 
*_BPP() == 1; but then again, maybe you don't plan on supporting 
sub-byte pixel formats anyway.

> +    stride = pixman_image_get_stride(res->image);
> +
> +    if (t2d.offset || t2d.r.x || t2d.r.y ||
> +        t2d.r.width != pixman_image_get_width(res->image)) {
> +        void *img_data = pixman_image_get_data(res->image);
> +        for (h = 0; h < t2d.r.height; h++) {
> +            src_offset = t2d.offset + stride * h;
> +            dst_offset = (t2d.r.y + h) * stride + (t2d.r.x * bpp);
> +
> +            iov_to_buf(res->iov, res->iov_cnt, src_offset,
> +                       (uint8_t *)img_data
> +                       + dst_offset, t2d.r.width * bpp);
> +        }
> +    } else {
> +        iov_to_buf(res->iov, res->iov_cnt, 0,
> +                   pixman_image_get_data(res->image),
> +                   pixman_image_get_stride(res->image)
> +                   * pixman_image_get_height(res->image));

Will this work with stride != t2d.r.width * bpp?

> +    }
> +}
> +
> +static void virtio_gpu_resource_flush(VirtIOGPU *g,
> +                                      struct virtio_gpu_ctrl_command *cmd)
> +{
> +    struct virtio_gpu_simple_resource *res;
> +    struct virtio_gpu_resource_flush rf;
> +    pixman_region16_t flush_region;
> +    int i;
> +
> +    VIRTIO_GPU_FILL_CMD(rf);
> +    trace_virtio_gpu_cmd_res_flush(rf.resource_id,
> +                                   rf.r.width, rf.r.height, rf.r.x, rf.r.y);
> +
> +    res = virtio_gpu_find_resource(g, rf.resource_id);
> +    if (!res) {
> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal resource specified %d\n",
> +                      __func__, rf.resource_id);
> +        cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
> +        return;
> +    }
> +
> +    if (rf.r.x > res->width ||
> +        rf.r.y > res->height ||
> +        rf.r.width > res->width ||
> +        rf.r.height > res->height ||
> +        rf.r.x + rf.r.width > res->width ||
> +        rf.r.y + rf.r.height > res->height) {
> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: flush bounds outside resource"
> +                      " bounds for resource %d: %d %d %d %d vs %d %d\n",
> +                      __func__, rf.resource_id, rf.r.x, rf.r.y,
> +                      rf.r.width, rf.r.height, res->width, res->height);
> +        cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
> +        return;
> +    }
> +
> +    pixman_region_init_rect(&flush_region,
> +                            rf.r.x, rf.r.y, rf.r.width, rf.r.height);
> +    for (i = 0; i < VIRTIO_GPU_MAX_SCANOUT; i++) {
> +        struct virtio_gpu_scanout *scanout;
> +        pixman_region16_t region, finalregion;
> +        pixman_box16_t *extents;
> +
> +        if (!(res->scanout_bitmask & (1 << i))) {
> +            continue;
> +        }
> +        scanout = &g->scanout[i];
> +
> +        pixman_region_init(&finalregion);
> +        pixman_region_init_rect(&region, scanout->x, scanout->y,
> +                                scanout->width, scanout->height);
> +
> +        pixman_region_intersect(&finalregion, &flush_region, &region);
> +        pixman_region_translate(&finalregion, -scanout->x, -scanout->y);
> +        extents = pixman_region_extents(&finalregion);
> +        /* work out the area we need to update for each console */
> +        dpy_gfx_update(g->scanout[i].con,
> +                       extents->x1, extents->y1,
> +                       extents->x2 - extents->x1,
> +                       extents->y2 - extents->y1);
> +
> +        pixman_region_fini(&region);
> +        pixman_region_fini(&finalregion);
> +    }
> +    pixman_region_fini(&flush_region);
> +}
> +
> +static void virtio_gpu_set_scanout(VirtIOGPU *g,
> +                                   struct virtio_gpu_ctrl_command *cmd)
> +{
> +    struct virtio_gpu_simple_resource *res;
> +    struct virtio_gpu_scanout *scanout;
> +    pixman_format_code_t format;
> +    uint32_t offset;
> +    int bpp;
> +    struct virtio_gpu_set_scanout ss;
> +
> +    VIRTIO_GPU_FILL_CMD(ss);
> +    trace_virtio_gpu_cmd_set_scanout(ss.scanout_id, ss.resource_id,
> +                                     ss.r.width, ss.r.height, ss.r.x, ss.r.y);
> +
> +    res = virtio_gpu_find_resource(g, ss.resource_id);

If ss.resource_id == 0, the result is unused; this function call could 
therefore be put after the next if block.

> +    g->enable = 1;
> +    if (ss.resource_id == 0) {
> +        scanout = &g->scanout[ss.scanout_id];
> +        if (g->scanout[ss.scanout_id].resource_id) {

Would be shorter as "if (scanout->resource_id)".

> +            res = virtio_gpu_find_resource(g, scanout->resource_id);
> +            if (res) {
> +                res->scanout_bitmask &= ~(1 << ss.scanout_id);
> +            }
> +        }
> +        if (ss.scanout_id == 0 ||
> +            ss.scanout_id >= g->conf.max_outputs) {
> +            qemu_log_mask(LOG_GUEST_ERROR,
> +                          "%s: illegal scanout id specified %d",
> +                          __func__, ss.scanout_id);
> +            cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID;
> +            return;
> +        }
> +        dpy_gfx_replace_surface(g->scanout[ss.scanout_id].con, NULL);
> +        scanout->ds = NULL;
> +        scanout->width = 0;
> +        scanout->height = 0;
> +        return;
> +    }
> +
> +    /* create a surface for this scanout */
> +    if (ss.scanout_id >= VIRTIO_GPU_MAX_SCANOUT ||
> +        ss.scanout_id >= g->conf.max_outputs) {
> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal scanout id specified %d",
> +                      __func__, ss.scanout_id);
> +        cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID;
> +        return;
> +    }
> +    if (!res) {
> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal resource specified %d\n",
> +                      __func__, ss.resource_id);
> +        cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
> +        return;
> +    }
> +
> +    if (ss.r.x > res->width ||
> +        ss.r.y > res->height ||
> +        ss.r.width > res->width ||
> +        ss.r.height > res->height ||
> +        ss.r.x + ss.r.width > res->width ||
> +        ss.r.y + ss.r.height > res->height) {
> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal scanout %d bounds for"
> +                      " resource %d, (%d,%d)+%d,%d vs %d %d\n",
> +                      __func__, ss.scanout_id, ss.resource_id, ss.r.x, ss.r.y,
> +                      ss.r.width, ss.r.height, res->width, res->height);
> +        cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
> +        return;
> +    }
> +
> +    scanout = &g->scanout[ss.scanout_id];
> +
> +    format = pixman_image_get_format(res->image);
> +    bpp = (PIXMAN_FORMAT_BPP(format) + 7) / 8;
> +    offset = (ss.r.x * bpp) + ss.r.y * pixman_image_get_stride(res->image);
> +    if (!scanout->ds || surface_data(scanout->ds)
> +        != ((uint8_t *)pixman_image_get_data(res->image) + offset) ||
> +        scanout->width != ss.r.width ||
> +        scanout->height != ss.r.height) {
> +        /* realloc the surface ptr */
> +        scanout->ds = qemu_create_displaysurface_from
> +            (ss.r.width, ss.r.height, format,
> +             pixman_image_get_stride(res->image),
> +             (uint8_t *)pixman_image_get_data(res->image) + offset);
> +        if (!scanout->ds) {
> +            cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
> +            return;
> +        }
> +        dpy_gfx_replace_surface(g->scanout[ss.scanout_id].con, scanout->ds);
> +    }
> +
> +    res->scanout_bitmask |= (1 << ss.scanout_id);
> +    scanout->resource_id = ss.resource_id;
> +    scanout->x = ss.r.x;
> +    scanout->y = ss.r.y;
> +    scanout->width = ss.r.width;
> +    scanout->height = ss.r.height;
> +}
> +
> +int virtio_gpu_create_mapping_iov(struct virtio_gpu_resource_attach_backing *ab,
> +                                  struct virtio_gpu_ctrl_command *cmd,
> +                                  struct iovec **iov)
> +{
> +    struct virtio_gpu_mem_entry *ents;
> +    size_t esize, s;
> +    int i;
> +
> +    esize = sizeof(*ents) * ab->nr_entries;

Can overflow (on 32 bit hosts).

(And this might be bad, because this function works just fine, and then 
either the for loop does something, or nr_entries is negative when 
casted to signed int, and then the for loop won't do anything; but 
res->iov_cnt (unsigned int) will be set to ab->nr_entries, so this may 
or may not be exploitable, but can probably lead to a crash)

> +    ents = g_malloc(esize);

And this may need to be g_try_malloc().

However, I think it's best to simply limit ab->nr_entries to some sane 
value (I guess it shouldn't be even in the double digits for a single 
resource, so restricting it to 256 or something seems sane to me...) and 
return an error to the guest if that limit is exceeded.

> +    s = iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num,
> +                   sizeof(*ab), ents, esize);
> +    if (s != esize) {
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: command data size incorrect %zu vs %zu\n",
> +                      __func__, s, esize);
> +        g_free(ents);
> +        return -1;
> +    }
> +
> +    *iov = g_malloc0(sizeof(struct iovec) * ab->nr_entries);

Can overflow just as the above.

Max

> +    for (i = 0; i < ab->nr_entries; i++) {
> +        hwaddr len = ents[i].length;
> +        (*iov)[i].iov_len = ents[i].length;
> +        (*iov)[i].iov_base = cpu_physical_memory_map(ents[i].addr, &len, 1);
> +        if (!(*iov)[i].iov_base || len != ents[i].length) {
> +            qemu_log_mask(LOG_GUEST_ERROR, "%s: failed to map MMIO memory for"
> +                          " resource %d element %d\n",
> +                          __func__, ab->resource_id, i);
> +            virtio_gpu_cleanup_mapping_iov(*iov, i);
> +            g_free(ents);
> +            g_free(*iov);
> +            *iov = NULL;
> +            return -1;
> +        }
> +    }
> +    g_free(ents);
> +    return 0;
> +}
> +
> +void virtio_gpu_cleanup_mapping_iov(struct iovec *iov, uint32_t count)
> +{
> +    int i;
> +
> +    for (i = 0; i < count; i++) {
> +        cpu_physical_memory_unmap(iov[i].iov_base, iov[i].iov_len, 1,
> +                                  iov[i].iov_len);
> +    }
> +}
> +
> +static void virtio_gpu_cleanup_mapping(struct virtio_gpu_simple_resource *res)
> +{
> +    virtio_gpu_cleanup_mapping_iov(res->iov, res->iov_cnt);
> +    g_free(res->iov);
> +    res->iov = NULL;
> +    res->iov_cnt = 0;
> +}
> +
> +static void
> +virtio_gpu_resource_attach_backing(VirtIOGPU *g,
> +                                   struct virtio_gpu_ctrl_command *cmd)
> +{
> +    struct virtio_gpu_simple_resource *res;
> +    struct virtio_gpu_resource_attach_backing ab;
> +    int ret;
> +
> +    VIRTIO_GPU_FILL_CMD(ab);
> +    trace_virtio_gpu_cmd_res_back_attach(ab.resource_id);
> +
> +    res = virtio_gpu_find_resource(g, ab.resource_id);
> +    if (!res) {
> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal resource specified %d\n",
> +                      __func__, ab.resource_id);
> +        cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
> +        return;
> +    }
> +
> +    ret = virtio_gpu_create_mapping_iov(&ab, cmd, &res->iov);
> +    if (ret != 0) {
> +        cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
> +        return;
> +    }
> +
> +    res->iov_cnt = ab.nr_entries;
> +}
> +
> +static void
> +virtio_gpu_resource_detach_backing(VirtIOGPU *g,
> +                                   struct virtio_gpu_ctrl_command *cmd)
> +{
> +    struct virtio_gpu_simple_resource *res;
> +    struct virtio_gpu_resource_detach_backing detach;
> +
> +    VIRTIO_GPU_FILL_CMD(detach);
> +    trace_virtio_gpu_cmd_res_back_detach(detach.resource_id);
> +
> +    res = virtio_gpu_find_resource(g, detach.resource_id);
> +    if (!res || !res->iov) {
> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal resource specified %d\n",
> +                      __func__, detach.resource_id);
> +        cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
> +        return;
> +    }
> +    virtio_gpu_cleanup_mapping(res);
> +}
> +
> +static void virtio_gpu_simple_process_cmd(VirtIOGPU *g,
> +                                          struct virtio_gpu_ctrl_command *cmd)
> +{
> +    VIRTIO_GPU_FILL_CMD(cmd->cmd_hdr);
> +
> +    switch (cmd->cmd_hdr.type) {
> +    case VIRTIO_GPU_CMD_GET_DISPLAY_INFO:
> +        virtio_gpu_get_display_info(g, cmd);
> +        break;
> +    case VIRTIO_GPU_CMD_RESOURCE_CREATE_2D:
> +        virtio_gpu_resource_create_2d(g, cmd);
> +        break;
> +    case VIRTIO_GPU_CMD_RESOURCE_UNREF:
> +        virtio_gpu_resource_unref(g, cmd);
> +        break;
> +    case VIRTIO_GPU_CMD_RESOURCE_FLUSH:
> +        virtio_gpu_resource_flush(g, cmd);
> +        break;
> +    case VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D:
> +        virtio_gpu_transfer_to_host_2d(g, cmd);
> +        break;
> +    case VIRTIO_GPU_CMD_SET_SCANOUT:
> +        virtio_gpu_set_scanout(g, cmd);
> +        break;
> +    case VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING:
> +        virtio_gpu_resource_attach_backing(g, cmd);
> +        break;
> +    case VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING:
> +        virtio_gpu_resource_detach_backing(g, cmd);
> +        break;
> +    default:
> +        cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
> +        break;
> +    }
> +    if (!cmd->finished) {
> +        virtio_gpu_ctrl_response_nodata(g, cmd, cmd->error ? cmd->error :
> +                                        VIRTIO_GPU_RESP_OK_NODATA);
> +    }
> +}
> +
> +static void virtio_gpu_handle_ctrl_cb(VirtIODevice *vdev, VirtQueue *vq)
> +{
> +    VirtIOGPU *g = VIRTIO_GPU(vdev);
> +    qemu_bh_schedule(g->ctrl_bh);
> +}
> +
> +static void virtio_gpu_handle_cursor_cb(VirtIODevice *vdev, VirtQueue *vq)
> +{
> +    VirtIOGPU *g = VIRTIO_GPU(vdev);
> +    qemu_bh_schedule(g->cursor_bh);
> +}
> +
> +static void virtio_gpu_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
> +{
> +    VirtIOGPU *g = VIRTIO_GPU(vdev);
> +    struct virtio_gpu_ctrl_command *cmd;
> +
> +    if (!virtio_queue_ready(vq)) {
> +        return;
> +    }
> +
> +    cmd = g_new(struct virtio_gpu_ctrl_command, 1);
> +    while (virtqueue_pop(vq, &cmd->elem)) {
> +        cmd->vq = vq;
> +        cmd->error = 0;
> +        cmd->finished = false;
> +        g->stats.requests++;
> +
> +        virtio_gpu_simple_process_cmd(g, cmd);
> +        if (!cmd->finished) {
> +            QTAILQ_INSERT_TAIL(&g->fenceq, cmd, next);
> +            g->stats.inflight++;
> +            if (g->stats.max_inflight < g->stats.inflight) {
> +                g->stats.max_inflight = g->stats.inflight;
> +            }
> +            fprintf(stderr, "inflight: %3d (+)\r", g->stats.inflight);
> +            cmd = g_new(struct virtio_gpu_ctrl_command, 1);
> +        }
> +    }
> +    g_free(cmd);
> +}
> +
> +static void virtio_gpu_ctrl_bh(void *opaque)
> +{
> +    VirtIOGPU *g = opaque;
> +    virtio_gpu_handle_ctrl(&g->parent_obj, g->ctrl_vq);
> +}
> +
> +static void virtio_gpu_handle_cursor(VirtIODevice *vdev, VirtQueue *vq)
> +{
> +    VirtIOGPU *g = VIRTIO_GPU(vdev);
> +    VirtQueueElement elem;
> +    size_t s;
> +    struct virtio_gpu_update_cursor cursor_info;
> +
> +    if (!virtio_queue_ready(vq)) {
> +        return;
> +    }
> +    while (virtqueue_pop(vq, &elem)) {
> +        s = iov_to_buf(elem.out_sg, elem.out_num, 0,
> +                       &cursor_info, sizeof(cursor_info));
> +        if (s != sizeof(cursor_info)) {
> +            qemu_log_mask(LOG_GUEST_ERROR,
> +                          "%s: cursor size incorrect %zu vs %zu\n",
> +                          __func__, s, sizeof(cursor_info));
> +        } else {
> +            update_cursor(g, &cursor_info);
> +        }
> +        virtqueue_push(vq, &elem, 0);
> +        virtio_notify(vdev, vq);
> +    }
> +}
> +
> +static void virtio_gpu_cursor_bh(void *opaque)
> +{
> +    VirtIOGPU *g = opaque;
> +    virtio_gpu_handle_cursor(&g->parent_obj, g->cursor_vq);
> +}
> +
> +static void virtio_gpu_invalidate_display(void *opaque)
> +{
> +}
> +
> +static void virtio_gpu_update_display(void *opaque)
> +{
> +}
> +
> +static void virtio_gpu_text_update(void *opaque, console_ch_t *chardata)
> +{
> +}
> +
> +static int virtio_gpu_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info)
> +{
> +    VirtIOGPU *g = opaque;
> +
> +    if (idx > g->conf.max_outputs) {
> +        return -1;
> +    }
> +
> +    g->req_state[idx].x = info->xoff;
> +    g->req_state[idx].y = info->yoff;
> +    g->req_state[idx].width = info->width;
> +    g->req_state[idx].height = info->height;
> +
> +    if (info->width && info->height) {
> +        g->enabled_output_bitmask |= (1 << idx);
> +    } else {
> +        g->enabled_output_bitmask &= ~(1 << idx);
> +    }
> +
> +    /* send event to guest */
> +    virtio_gpu_notify_event(g, VIRTIO_GPU_EVENT_DISPLAY);
> +    return 0;
> +}
> +
> +const GraphicHwOps virtio_gpu_ops = {
> +    .invalidate = virtio_gpu_invalidate_display,
> +    .gfx_update = virtio_gpu_update_display,
> +    .text_update = virtio_gpu_text_update,
> +    .ui_info = virtio_gpu_ui_info,
> +};
> +
> +static void virtio_gpu_device_realize(DeviceState *qdev, Error **errp)
> +{
> +    VirtIODevice *vdev = VIRTIO_DEVICE(qdev);
> +    VirtIOGPU *g = VIRTIO_GPU(qdev);
> +    int i;
> +
> +    g->config_size = sizeof(struct virtio_gpu_config);
> +    g->virtio_config.num_scanouts = g->conf.max_outputs;
> +    virtio_init(VIRTIO_DEVICE(g), "virtio-gpu", VIRTIO_ID_GPU,
> +                g->config_size);
> +
> +    g->req_state[0].width = 1024;
> +    g->req_state[0].height = 768;
> +
> +    g->ctrl_vq   = virtio_add_queue(vdev, 256, virtio_gpu_handle_ctrl_cb);
> +    g->cursor_vq = virtio_add_queue(vdev, 256, virtio_gpu_handle_cursor_cb);
> +
> +    g->ctrl_bh = qemu_bh_new(virtio_gpu_ctrl_bh, g);
> +    g->cursor_bh = qemu_bh_new(virtio_gpu_cursor_bh, g);
> +    QTAILQ_INIT(&g->reslist);
> +    QTAILQ_INIT(&g->fenceq);
> +
> +    g->enabled_output_bitmask = 1;
> +    g->qdev = qdev;
> +
> +    for (i = 0; i < g->conf.max_outputs; i++) {
> +        g->scanout[i].con =
> +            graphic_console_init(DEVICE(g), i, &virtio_gpu_ops, g);
> +        if (i > 0) {
> +            dpy_gfx_replace_surface(g->scanout[i].con, NULL);
> +        }
> +    }
> +}
> +
> +static void virtio_gpu_instance_init(Object *obj)
> +{
> +}
> +
> +static void virtio_gpu_reset(VirtIODevice *vdev)
> +{
> +    VirtIOGPU *g = VIRTIO_GPU(vdev);
> +    struct virtio_gpu_simple_resource *res, *tmp;
> +    int i;
> +
> +    g->enable = 0;
> +
> +    QTAILQ_FOREACH_SAFE(res, &g->reslist, next, tmp) {
> +        virtio_gpu_resource_destroy(g, res);
> +    }
> +    for (i = 0; i < g->conf.max_outputs; i++) {
> +#if 0
> +        g->req_state[i].x = 0;
> +        g->req_state[i].y = 0;
> +        if (i == 0) {
> +            g->req_state[0].width = 1024;
> +            g->req_state[0].height = 768;
> +        } else {
> +            g->req_state[i].width = 0;
> +            g->req_state[i].height = 0;
> +        }
> +#endif
> +        g->scanout[i].resource_id = 0;
> +        g->scanout[i].width = 0;
> +        g->scanout[i].height = 0;
> +        g->scanout[i].x = 0;
> +        g->scanout[i].y = 0;
> +        g->scanout[i].ds = NULL;
> +    }
> +    g->enabled_output_bitmask = 1;
> +}
> +
> +static Property virtio_gpu_properties[] = {
> +    DEFINE_VIRTIO_GPU_PROPERTIES(VirtIOGPU, conf),
> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
> +static void virtio_gpu_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
> +
> +    vdc->realize = virtio_gpu_device_realize;
> +    vdc->get_config = virtio_gpu_get_config;
> +    vdc->set_config = virtio_gpu_set_config;
> +    vdc->get_features = virtio_gpu_get_features;
> +    vdc->set_features = virtio_gpu_set_features;
> +
> +    vdc->reset = virtio_gpu_reset;
> +
> +    dc->props = virtio_gpu_properties;
> +}
> +
> +static const TypeInfo virtio_gpu_info = {
> +    .name = TYPE_VIRTIO_GPU,
> +    .parent = TYPE_VIRTIO_DEVICE,
> +    .instance_size = sizeof(VirtIOGPU),
> +    .instance_init = virtio_gpu_instance_init,
> +    .class_init = virtio_gpu_class_init,
> +};
> +
> +static void virtio_register_types(void)
> +{
> +    type_register_static(&virtio_gpu_info);
> +}
> +
> +type_init(virtio_register_types)
> +
> +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_ctrl_hdr)                != 24);
> +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_update_cursor)           != 56);
> +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_unref)          != 32);
> +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_create_2d)      != 40);
> +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_set_scanout)             != 48);
> +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_flush)          != 48);
> +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_transfer_to_host_2d)     != 56);
> +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_mem_entry)               != 16);
> +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_attach_backing) != 32);
> +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resource_detach_backing) != 32);
> +QEMU_BUILD_BUG_ON(sizeof(struct virtio_gpu_resp_display_info)       != 408);
> diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h
> new file mode 100644
> index 0000000..5d26ca9
> --- /dev/null
> +++ b/include/hw/virtio/virtio-gpu.h
> @@ -0,0 +1,147 @@
> +/*
> + * Virtio GPU Device
> + *
> + * Copyright Red Hat, Inc. 2013-2014
> + *
> + * Authors:
> + *     Dave Airlie<airlied@redhat.com>
> + *     Gerd Hoffmann<kraxel@redhat.com>
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2.
> + * See the COPYING file in the top-level directory.
> + */
> +
> +#ifndef _QEMU_VIRTIO_VGA_H
> +#define _QEMU_VIRTIO_VGA_H
> +
> +#include "qemu/queue.h"
> +#include "ui/qemu-pixman.h"
> +#include "ui/console.h"
> +#include "hw/virtio/virtio.h"
> +#include "hw/pci/pci.h"
> +
> +#include "hw/virtio/virtgpu_hw.h"
> +#define TYPE_VIRTIO_GPU "virtio-gpu-device"
> +#define VIRTIO_GPU(obj)                                        \
> +        OBJECT_CHECK(VirtIOGPU, (obj), TYPE_VIRTIO_GPU)
> +
> +#define VIRTIO_ID_GPU 16
> +
> +#define VIRTIO_GPU_MAX_RES 16
> +
> +#define VIRTIO_GPU_MAX_SCANOUT 4
> +
> +struct virtio_gpu_simple_resource {
> +    uint32_t resource_id;
> +    uint32_t width;
> +    uint32_t height;
> +    uint32_t format;
> +    struct iovec *iov;
> +    unsigned int iov_cnt;
> +    uint32_t scanout_bitmask;
> +    pixman_image_t *image;
> +    QTAILQ_ENTRY(virtio_gpu_simple_resource) next;
> +};
> +
> +struct virtio_gpu_scanout {
> +    QemuConsole *con;
> +    DisplaySurface *ds;
> +    uint32_t width, height;
> +    int x, y;
> +    int invalidate;
> +    uint32_t resource_id;
> +    QEMUCursor *current_cursor;
> +};
> +
> +struct virtio_gpu_requested_state {
> +    uint32_t width, height;
> +    int x, y;
> +};
> +
> +struct virtio_gpu_conf {
> +    uint32_t max_outputs;
> +};
> +
> +struct virtio_gpu_ctrl_command {
> +    VirtQueueElement elem;
> +    VirtQueue *vq;
> +    struct virtio_gpu_ctrl_hdr cmd_hdr;
> +    uint32_t error;
> +    bool finished;
> +    QTAILQ_ENTRY(virtio_gpu_ctrl_command) next;
> +};
> +
> +typedef struct VirtIOGPU {
> +    VirtIODevice parent_obj;
> +
> +    QEMUBH *ctrl_bh;
> +    QEMUBH *cursor_bh;
> +    VirtQueue *ctrl_vq;
> +    VirtQueue *cursor_vq;
> +
> +    int enable;
> +
> +    int config_size;
> +    DeviceState *qdev;
> +
> +    QTAILQ_HEAD(, virtio_gpu_simple_resource) reslist;
> +    QTAILQ_HEAD(, virtio_gpu_ctrl_command) fenceq;
> +
> +    struct virtio_gpu_scanout scanout[VIRTIO_GPU_MAX_SCANOUT];
> +    struct virtio_gpu_requested_state req_state[VIRTIO_GPU_MAX_SCANOUT];
> +
> +    struct virtio_gpu_conf conf;
> +    int enabled_output_bitmask;
> +    struct virtio_gpu_config virtio_config;
> +
> +    QEMUTimer *fence_poll;
> +    QEMUTimer *print_stats;
> +
> +    struct {
> +        uint32_t inflight;
> +        uint32_t max_inflight;
> +        uint32_t requests;
> +        uint32_t req_3d;
> +        uint32_t bytes_3d;
> +    } stats;
> +} VirtIOGPU;
> +
> +extern const GraphicHwOps virtio_gpu_ops;
> +
> +/* to share between PCI and VGA */
> +#define DEFINE_VIRTIO_GPU_PCI_PROPERTIES(_state)               \
> +    DEFINE_PROP_BIT("ioeventfd", _state, flags,                \
> +                    VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, false), \
> +    DEFINE_PROP_UINT32("vectors", _state, nvectors, 3)
> +
> +#define DEFINE_VIRTIO_GPU_PROPERTIES(_state, _conf_field)               \
> +    DEFINE_PROP_UINT32("max_outputs", _state, _conf_field.max_outputs, 2)
> +
> +#define VIRTIO_GPU_FILL_CMD(out) do {                                   \
> +        size_t s;                                                       \
> +        s = iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num, 0,          \
> +                       &out, sizeof(out));                              \
> +        if (s != sizeof(out)) {                                         \
> +            qemu_log_mask(LOG_GUEST_ERROR,                              \
> +                          "%s: command size incorrect %zu vs %zu\n",    \
> +                          __func__, s, sizeof(out));                    \
> +            return;                                                     \
> +        }                                                               \
> +    } while (0)
> +
> +/* virtio-gpu.c */
> +void virtio_gpu_ctrl_response(VirtIOGPU *g,
> +                              struct virtio_gpu_ctrl_command *cmd,
> +                              struct virtio_gpu_ctrl_hdr *resp,
> +                              size_t resp_len);
> +void virtio_gpu_ctrl_response_nodata(VirtIOGPU *g,
> +                                     struct virtio_gpu_ctrl_command *cmd,
> +                                     enum virtio_gpu_ctrl_type type);
> +void virtio_gpu_get_display_info(VirtIOGPU *g,
> +                                 struct virtio_gpu_ctrl_command *cmd);
> +int virtio_gpu_create_mapping_iov(struct virtio_gpu_resource_attach_backing *ab,
> +                                  struct virtio_gpu_ctrl_command *cmd,
> +                                  struct iovec **iov);
> +void virtio_gpu_cleanup_mapping_iov(struct iovec *iov, uint32_t count);
> +
> +#endif
> diff --git a/trace-events b/trace-events
> index f87b077..e576c73 100644
> --- a/trace-events
> +++ b/trace-events
> @@ -1163,6 +1163,20 @@ vmware_scratch_read(uint32_t index, uint32_t value) "index %d, value 0x%x"
>   vmware_scratch_write(uint32_t index, uint32_t value) "index %d, value 0x%x"
>   vmware_setmode(uint32_t w, uint32_t h, uint32_t bpp) "%dx%d @ %d bpp"
>   
> +# hw/display/virtio-gpu.c
> +virtio_gpu_cmd_get_display_info(void) ""
> +virtio_gpu_cmd_get_caps(void) ""
> +virtio_gpu_cmd_set_scanout(uint32_t id, uint32_t res, uint32_t w, uint32_t h, uint32_t x, uint32_t y) "id %d, res 0x%x, w %d, h %d, x %d, y %d"
> +virtio_gpu_cmd_res_create_2d(uint32_t res, uint32_t fmt, uint32_t w, uint32_t h) "res 0x%x, fmt 0x%x, w %d, h %d"
> +virtio_gpu_cmd_res_create_3d(uint32_t res, uint32_t fmt, uint32_t w, uint32_t h, uint32_t d) "res 0x%x, fmt 0x%x, w %d, h %d, d %d"
> +virtio_gpu_cmd_res_unref(uint32_t res) "res 0x%x"
> +virtio_gpu_cmd_res_back_attach(uint32_t res) "res 0x%x"
> +virtio_gpu_cmd_res_back_detach(uint32_t res) "res 0x%x"
> +virtio_gpu_cmd_res_xfer_toh_2d(uint32_t res) "res 0x%x"
> +virtio_gpu_cmd_res_flush(uint32_t res, uint32_t w, uint32_t h, uint32_t x, uint32_t y) "res 0x%x, w %d, h %d, x %d, y %d"
> +virtio_gpu_fence_ctrl(uint64_t fence, uint32_t type) "fence 0x%" PRIx64 ", type 0x%x"
> +virtio_gpu_fence_resp(uint64_t fence) "fence 0x%" PRIx64
> +
>   # savevm.c
>   qemu_loadvm_state_section(unsigned int section_type) "%d"
>   qemu_loadvm_state_section_partend(uint32_t section_id) "%u"

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [Qemu-devel] [RfC PATCH 07/15] virtio-gpu-pci: add virtio pci support
  2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 07/15] virtio-gpu-pci: add virtio pci support Gerd Hoffmann
@ 2015-02-26 16:25   ` Max Reitz
  2015-02-27 11:13     ` Gerd Hoffmann
  0 siblings, 1 reply; 44+ messages in thread
From: Max Reitz @ 2015-02-26 16:25 UTC (permalink / raw)
  To: Gerd Hoffmann, qemu-devel
  Cc: Dave Airlie, Anthony Liguori, Michael S. Tsirkin

On 2015-02-23 at 05:23, Gerd Hoffmann wrote:
> This patch adds virtio-gpu-pci, which is the pci proxy for the virtio
> gpu device.  With this patch in place virtio-gpu is functional.  You
> need a linux guest with a virtio-gpu driver though, and output will
> appear pretty late in boot, once the kernel initialized drm and fbcon.
>
> Written by Dave Airlie and Gerd Hoffmann.
>
> Signed-off-by: Dave Airlie <airlied@redhat.com>
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
>   hw/display/Makefile.objs    |  1 +
>   hw/display/virtio-gpu-pci.c | 71 +++++++++++++++++++++++++++++++++++++++++++++
>   hw/virtio/virtio-pci.h      | 15 ++++++++++
>   include/hw/pci/pci.h        |  1 +
>   4 files changed, 88 insertions(+)
>   create mode 100644 hw/display/virtio-gpu-pci.c
>
> diff --git a/hw/display/Makefile.objs b/hw/display/Makefile.objs
> index 6990634..ab6b791 100644
> --- a/hw/display/Makefile.objs
> +++ b/hw/display/Makefile.objs
> @@ -35,3 +35,4 @@ obj-$(CONFIG_VGA) += vga.o
>   common-obj-$(CONFIG_QXL) += qxl.o qxl-logger.o qxl-render.o
>   
>   obj-$(CONFIG_VIRTIO) += virtio-gpu.o
> +obj-$(CONFIG_VIRTIO_PCI) += virtio-gpu-pci.o
> diff --git a/hw/display/virtio-gpu-pci.c b/hw/display/virtio-gpu-pci.c
> new file mode 100644
> index 0000000..77c5e06
> --- /dev/null
> +++ b/hw/display/virtio-gpu-pci.c
> @@ -0,0 +1,71 @@
> +/*
> + * Virtio video device
> + *
> + * Copyright Red Hat
> + *
> + * Authors:
> + *  Dave Airlie
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2.  See
> + * the COPYING file in the top-level directory.
> + *
> + */
> +#include "hw/pci/pci.h"
> +#include "hw/virtio/virtio.h"
> +#include "hw/virtio/virtio-bus.h"
> +#include "hw/virtio/virtio-pci.h"
> +#include "hw/virtio/virtio-gpu.h"
> +
> +static Property virtio_gpu_pci_properties[] = {
> +    DEFINE_VIRTIO_GPU_PROPERTIES(VirtIOGPUPCI, vdev.conf),
> +    DEFINE_VIRTIO_GPU_PCI_PROPERTIES(VirtIOPCIProxy),
> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
> +static int virtio_gpu_pci_init(VirtIOPCIProxy *vpci_dev)
> +{
> +    VirtIOGPUPCI *vgpu = VIRTIO_GPU_PCI(vpci_dev);
> +    DeviceState *vdev = DEVICE(&vgpu->vdev);
> +
> +    qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
> +    if (qdev_init(vdev) < 0) {
> +        return -1;
> +    }
> +    return 0;
> +}
> +
> +static void virtio_gpu_pci_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
> +    PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
> +
> +    set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
> +    dc->props = virtio_gpu_pci_properties;
> +    k->init = virtio_gpu_pci_init;
> +    pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
> +    pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_GPU;
> +    pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
> +    pcidev_k->class_id = PCI_CLASS_DISPLAY_OTHER;
> +}
> +
> +static void virtio_gpu_initfn(Object *obj)
> +{
> +    VirtIOGPUPCI *dev = VIRTIO_GPU_PCI(obj);
> +    object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_GPU);
> +    object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
> +}
> +
> +static const TypeInfo virtio_gpu_pci_info = {
> +    .name = TYPE_VIRTIO_GPU_PCI,
> +    .parent = TYPE_VIRTIO_PCI,
> +    .instance_size = sizeof(VirtIOGPUPCI),
> +    .instance_init = virtio_gpu_initfn,
> +    .class_init = virtio_gpu_pci_class_init,
> +};
> +
> +static void virtio_gpu_pci_register_types(void)
> +{
> +    type_register_static(&virtio_gpu_pci_info);
> +}
> +type_init(virtio_gpu_pci_register_types)
> diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h
> index a273c33..edb4752 100644
> --- a/hw/virtio/virtio-pci.h
> +++ b/hw/virtio/virtio-pci.h
> @@ -24,6 +24,7 @@
>   #include "hw/virtio/virtio-balloon.h"
>   #include "hw/virtio/virtio-bus.h"
>   #include "hw/virtio/virtio-9p.h"
> +#include "hw/virtio/virtio-gpu.h"
>   #ifdef CONFIG_VIRTFS
>   #include "hw/9pfs/virtio-9p.h"
>   #endif
> @@ -39,6 +40,7 @@ typedef struct VirtIOSerialPCI VirtIOSerialPCI;
>   typedef struct VirtIONetPCI VirtIONetPCI;
>   typedef struct VHostSCSIPCI VHostSCSIPCI;
>   typedef struct VirtIORngPCI VirtIORngPCI;
> +typedef struct VirtIOGPUPCI VirtIOGPUPCI;
>   
>   /* virtio-pci-bus */
>   
> @@ -227,6 +229,19 @@ struct VirtIORngPCI {
>       VirtIORNG vdev;
>   };
>   
> +/*
> + * virtio-gpu-pci: This extends VirtioPCIProxy.
> + */
> +#define TYPE_VIRTIO_GPU_PCI "virtio-gpu-pci"
> +#define VIRTIO_GPU_PCI(obj) \
> +        OBJECT_CHECK(VirtIOGPUPCI, (obj), TYPE_VIRTIO_GPU_PCI)
> +
> +struct VirtIOGPUPCI {
> +    VirtIOPCIProxy parent_obj;
> +    VirtIOGPU vdev;
> +};
> +
> +
>   /* Virtio ABI version, if we increment this, we break the guest driver. */
>   #define VIRTIO_PCI_ABI_VERSION          0
>   
> diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h
> index bdee464..4a18ef5 100644
> --- a/include/hw/pci/pci.h
> +++ b/include/hw/pci/pci.h
> @@ -81,6 +81,7 @@
>   #define PCI_DEVICE_ID_VIRTIO_SCSI        0x1004
>   #define PCI_DEVICE_ID_VIRTIO_RNG         0x1005
>   #define PCI_DEVICE_ID_VIRTIO_9P          0x1009
> +#define PCI_DEVICE_ID_VIRTIO_GPU         0x1010
>   
>   #define PCI_VENDOR_ID_REDHAT             0x1b36
>   #define PCI_DEVICE_ID_REDHAT_BRIDGE      0x0001

Would you mind adding this to docs/specs/pci-ids.txt?

Max

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [Qemu-devel] [RfC PATCH 01/15] virtio-pci: add flags to enable/disable legacy/modern
  2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 01/15] virtio-pci: add flags to enable/disable legacy/modern Gerd Hoffmann
@ 2015-02-26 16:41   ` Max Reitz
  2015-02-27 11:15     ` Gerd Hoffmann
  2015-03-02 12:34   ` Michael S. Tsirkin
  1 sibling, 1 reply; 44+ messages in thread
From: Max Reitz @ 2015-02-26 16:41 UTC (permalink / raw)
  To: Gerd Hoffmann, qemu-devel; +Cc: Anthony Liguori, Michael S. Tsirkin

On 2015-02-23 at 05:23, Gerd Hoffmann wrote:
> Add VIRTIO_PCI_FLAG_DISABLE_LEGACY and VIRTIO_PCI_FLAG_DISABLE_MODERN
> for VirtIOPCIProxy->flags.  Also add properties for them.  They can be
> used to disable modern (virtio 1.0) or legacy (virtio 0.9) modes.  By
> default both are advertized and the guest driver can choose.
>
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
>   hw/virtio/virtio-pci.c | 46 +++++++++++++++++++++++++++++++++-------------
>   hw/virtio/virtio-pci.h |  6 ++++++
>   2 files changed, 39 insertions(+), 13 deletions(-)
>
> diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
> index 4c9a0b8..6c0c650 100644
> --- a/hw/virtio/virtio-pci.c
> +++ b/hw/virtio/virtio-pci.c
> @@ -1233,6 +1233,8 @@ static void virtio_pci_device_plugged(DeviceState *d)
>   {
>       VirtIOPCIProxy *proxy = VIRTIO_PCI(d);
>       VirtioBusState *bus = &proxy->bus;
> +    bool legacy = !(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_LEGACY);
> +    bool modern = !(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_MODERN);
>       uint8_t *config;
>       uint32_t size;
>   
> @@ -1240,13 +1242,24 @@ static void virtio_pci_device_plugged(DeviceState *d)
>       if (proxy->class_code) {
>           pci_config_set_class(config, proxy->class_code);
>       }
> -    pci_set_word(config + PCI_SUBSYSTEM_VENDOR_ID,
> -                 pci_get_word(config + PCI_VENDOR_ID));
> -    pci_set_word(config + PCI_SUBSYSTEM_ID, virtio_bus_get_vdev_id(bus));
> +
> +    if (legacy) {
> +        /* legacy and transitional */
> +        pci_set_word(config + PCI_SUBSYSTEM_VENDOR_ID,
> +                     pci_get_word(config + PCI_VENDOR_ID));
> +        pci_set_word(config + PCI_SUBSYSTEM_ID, virtio_bus_get_vdev_id(bus));
> +    } else {
> +        /* pure virtio-1.0 */
> +        pci_set_word(config + PCI_VENDOR_ID,
> +                     PCI_VENDOR_ID_REDHAT_QUMRANET);
> +        pci_set_word(config + PCI_DEVICE_ID,
> +                     0x1040 + virtio_bus_get_vdev_id(bus));
> +        pci_config_set_revision(config, 1);
> +    }

Hm, the virtio 1.0 specification from December 2013 states (4.1.1 PCI 
Device Discovery):

 > Any PCI device with Vendor ID 0x1AF4, and Device ID 0x1000 through 
0x103F inclusive is a virtio device.

 > The Subsystem Device ID indicates which virtio device is supported by 
the device. The Subsystem Vendor
 > ID SHOULD reflect the PCI Vendor ID of the environment (it's 
currently only used for informational purposes
 > by the driver).

So you seem to be following a completely different model here by setting 
the device ID to something above 0x103f and not setting subsytem device 
or vendor ID. Because of that device ID, this won't conflict with this 
part of the specification; but it seems that I'm missing some part of it 
which explains why you're doing this the way you're doing it... Can you 
help me with that?

Max

>       config[PCI_INTERRUPT_PIN] = 1;
>   
>   
> -    if (1) { /* TODO: Make this optional, dependent on virtio 1.0 */
> +    if (modern) {
>           struct virtio_pci_cap common = {
>               .cfg_type = VIRTIO_PCI_CAP_COMMON_CFG,
>               .cap_len = sizeof common,
> @@ -1359,17 +1372,20 @@ static void virtio_pci_device_plugged(DeviceState *d)
>   
>       proxy->pci_dev.config_write = virtio_write_config;
>   
> -    size = VIRTIO_PCI_REGION_SIZE(&proxy->pci_dev)
> -         + virtio_bus_get_vdev_config_len(bus);
> -    if (size & (size - 1)) {
> -        size = 1 << qemu_fls(size);
> -    }
> +    if (legacy) {
> +        size = VIRTIO_PCI_REGION_SIZE(&proxy->pci_dev)
> +            + virtio_bus_get_vdev_config_len(bus);
> +        if (size & (size - 1)) {
> +            size = 1 << qemu_fls(size);
> +        }
>   
> -    memory_region_init_io(&proxy->bar, OBJECT(proxy), &virtio_pci_config_ops,
> -                          proxy, "virtio-pci", size);
> +        memory_region_init_io(&proxy->bar, OBJECT(proxy),
> +                              &virtio_pci_config_ops,
> +                              proxy, "virtio-pci", size);
>   
> -    pci_register_bar(&proxy->pci_dev, 0, PCI_BASE_ADDRESS_SPACE_IO,
> -                     &proxy->bar);
> +        pci_register_bar(&proxy->pci_dev, 0, PCI_BASE_ADDRESS_SPACE_IO,
> +                         &proxy->bar);
> +    }
>   
>       if (!kvm_has_many_ioeventfds()) {
>           proxy->flags &= ~VIRTIO_PCI_FLAG_USE_IOEVENTFD;
> @@ -1416,6 +1432,10 @@ static void virtio_pci_reset(DeviceState *qdev)
>   static Property virtio_pci_properties[] = {
>       DEFINE_PROP_BIT("virtio-pci-bus-master-bug-migration", VirtIOPCIProxy, flags,
>                       VIRTIO_PCI_FLAG_BUS_MASTER_BUG_MIGRATION_BIT, false),
> +    DEFINE_PROP_BIT("disable-legacy", VirtIOPCIProxy, flags,
> +                    VIRTIO_PCI_FLAG_DISABLE_LEGACY_BIT, false),
> +    DEFINE_PROP_BIT("disable-modern", VirtIOPCIProxy, flags,
> +                    VIRTIO_PCI_FLAG_DISABLE_MODERN_BIT, false),
>       DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
>       DEFINE_PROP_END_OF_LIST(),
>   };
> diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h
> index 2cddd6a..3068a63 100644
> --- a/hw/virtio/virtio-pci.h
> +++ b/hw/virtio/virtio-pci.h
> @@ -63,6 +63,12 @@ typedef struct VirtioBusClass VirtioPCIBusClass;
>   #define VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT 1
>   #define VIRTIO_PCI_FLAG_USE_IOEVENTFD   (1 << VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT)
>   
> +/* virtio version flags */
> +#define VIRTIO_PCI_FLAG_DISABLE_LEGACY_BIT 2
> +#define VIRTIO_PCI_FLAG_DISABLE_MODERN_BIT 3
> +#define VIRTIO_PCI_FLAG_DISABLE_LEGACY (1 << VIRTIO_PCI_FLAG_DISABLE_LEGACY_BIT)
> +#define VIRTIO_PCI_FLAG_DISABLE_MODERN (1 << VIRTIO_PCI_FLAG_DISABLE_MODERN_BIT)
> +
>   typedef struct {
>       MSIMessage msg;
>       int virq;

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [Qemu-devel] [RfC PATCH 08/15] virtio-gpu-pci: virtio-1.0 adaptions [fixup]
  2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 08/15] virtio-gpu-pci: virtio-1.0 adaptions [fixup] Gerd Hoffmann
@ 2015-02-26 16:46   ` Max Reitz
  2015-02-27 11:18     ` Gerd Hoffmann
  0 siblings, 1 reply; 44+ messages in thread
From: Max Reitz @ 2015-02-26 16:46 UTC (permalink / raw)
  To: Gerd Hoffmann, qemu-devel; +Cc: Anthony Liguori, Michael S. Tsirkin

On 2015-02-23 at 05:23, Gerd Hoffmann wrote:
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
>   hw/display/virtio-gpu-pci.c | 11 ++++-------
>   1 file changed, 4 insertions(+), 7 deletions(-)
>
> diff --git a/hw/display/virtio-gpu-pci.c b/hw/display/virtio-gpu-pci.c
> index 77c5e06..791ee8b 100644
> --- a/hw/display/virtio-gpu-pci.c
> +++ b/hw/display/virtio-gpu-pci.c
> @@ -28,10 +28,10 @@ static int virtio_gpu_pci_init(VirtIOPCIProxy *vpci_dev)
>       DeviceState *vdev = DEVICE(&vgpu->vdev);
>   
>       qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
> -    if (qdev_init(vdev) < 0) {
> -        return -1;
> -    }
> -    return 0;
> +    /* force virtio-1.0 */
> +    vpci_dev->flags &= ~VIRTIO_PCI_FLAG_DISABLE_MODERN;
> +    vpci_dev->flags |= VIRTIO_PCI_FLAG_DISABLE_LEGACY;
> +    return qdev_init(vdev);
>   }
>   
>   static void virtio_gpu_pci_class_init(ObjectClass *klass, void *data)
> @@ -43,9 +43,6 @@ static void virtio_gpu_pci_class_init(ObjectClass *klass, void *data)
>       set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories);
>       dc->props = virtio_gpu_pci_properties;
>       k->init = virtio_gpu_pci_init;
> -    pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
> -    pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_GPU;
> -    pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;

So I guess this is the reason why you didn't update pci-ids.txt in patch 7.

This seems to be in line with the changes made in patch 1; however, I 
fail to see where VirtIODevice.device_id is set so that 
virtio_bus_get_vdev_id() returns it when called from 
virtio_pci_device_plugged()... Maybe I'll find it yet.

Max

>       pcidev_k->class_id = PCI_CLASS_DISPLAY_OTHER;
>   }

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [Qemu-devel] [RfC PATCH 12/15] virtio-vga: add vgabios configuration
  2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 12/15] virtio-vga: add vgabios configuration Gerd Hoffmann
@ 2015-02-26 18:13   ` Max Reitz
  2015-02-27 11:25     ` Gerd Hoffmann
  0 siblings, 1 reply; 44+ messages in thread
From: Max Reitz @ 2015-02-26 18:13 UTC (permalink / raw)
  To: Gerd Hoffmann, qemu-devel

On 2015-02-23 at 05:23, Gerd Hoffmann wrote:
> Add seavgabios configuration for virtio-vga,
> hook up the new vgabios in the makefiles.
>
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
>   Makefile               | 2 +-
>   roms/Makefile          | 2 +-
>   roms/config.vga-virtio | 6 ++++++
>   3 files changed, 8 insertions(+), 2 deletions(-)
>   create mode 100644 roms/config.vga-virtio
>
> diff --git a/Makefile b/Makefile
> index 6817c6f..cc01719 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -337,7 +337,7 @@ bepo    cz
>   
>   ifdef INSTALL_BLOBS
>   BLOBS=bios.bin bios-256k.bin sgabios.bin vgabios.bin vgabios-cirrus.bin \
> -vgabios-stdvga.bin vgabios-vmware.bin vgabios-qxl.bin \
> +vgabios-stdvga.bin vgabios-vmware.bin vgabios-qxl.bin vgabios-virtio.bin \
>   acpi-dsdt.aml q35-acpi-dsdt.aml \
>   ppc_rom.bin openbios-sparc32 openbios-sparc64 openbios-ppc QEMU,tcx.bin QEMU,cgthree.bin \
>   pxe-e1000.rom pxe-eepro100.rom pxe-ne2k_pci.rom \
> diff --git a/roms/Makefile b/roms/Makefile
> index 610b534..c76cd5b 100644
> --- a/roms/Makefile
> +++ b/roms/Makefile
> @@ -1,5 +1,5 @@
>   
> -vgabios_variants := stdvga cirrus vmware qxl isavga
> +vgabios_variants := stdvga cirrus vmware qxl isavga virtio
>   vgabios_targets  := $(subst -isavga,,$(patsubst %,vgabios-%.bin,$(vgabios_variants)))
>   pxerom_variants  := e1000 eepro100 ne2k_pci pcnet rtl8139 virtio
>   pxerom_targets   := 8086100e 80861209 10500940 10222000 10ec8139 1af41000
> diff --git a/roms/config.vga-virtio b/roms/config.vga-virtio
> new file mode 100644
> index 0000000..9a78983
> --- /dev/null
> +++ b/roms/config.vga-virtio
> @@ -0,0 +1,6 @@
> +CONFIG_BUILD_VGABIOS=y
> +CONFIG_VGA_BOCHS=y
> +CONFIG_VGA_PCI=y
> +CONFIG_OVERRIDE_PCI_ID=y
> +CONFIG_VGA_VID=0x1af4
> +CONFIG_VGA_DID=0x1010

Will this device ID work, even with your fixups regarding the PCI device ID?

Max

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [Qemu-devel] [RfC PATCH 00/15] virtio-gpu:
  2015-02-23 10:23 [Qemu-devel] [RfC PATCH 00/15] virtio-gpu: Gerd Hoffmann
                   ` (14 preceding siblings ...)
  2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 15/15] [hack] virtio-gpu: maskerade as -device VGA Gerd Hoffmann
@ 2015-02-26 18:40 ` Max Reitz
  2015-02-27 11:30   ` Gerd Hoffmann
  15 siblings, 1 reply; 44+ messages in thread
From: Max Reitz @ 2015-02-26 18:40 UTC (permalink / raw)
  To: Gerd Hoffmann, qemu-devel

On 2015-02-23 at 05:23, Gerd Hoffmann wrote:
>    Hi,
>
> After a loooong break, here is the next version of virtio-gpu patches.
> It is the first batch, with the 2d bits, virgl (3d/opengl) support will
> follow later on.
>
> The dust of the virtio-1.0 merge has mostly settled, even though not
> all virtio-1.0 bits are upstream yet (main reason why this is RfC).  My
> plan is to get virtio-gpu merged upstream as soon as all dependencies
> are in.
>
> This series applies on top of mst's virtio-1.0 branch.
>
> Patches 1-4 are virtio-pci patches which have been posted separately
> already, included here because the virtio-gpu patches depend on them.
>
> Patches 5-14 are virtio-gpu and virtio-vga patches.  Patches 8+10 with
> the virtio-1.0 changes depend on patches 1-4.  I've kept them separate
> for now, to simplify review and also to make adaptions easier in case
> patches 1-4 are changed during review.  Patch series is not fully
> bisectable because of this.  For the non-RfC patch series they will of
> course be squashed in.
>
> Patch 15 is a dirty hack to simplify testing with libvirt, this will
> be dropped for the merge, we'll need proper libvirt support instead.
>
> If you wanna play with this, here are host + guest git trees for your
> convinience:
>      git://git.kraxel.org/qemu tags/virtio-gpu-rfc-2015-02-23
>      git://git.kraxel.org/linux virtio-gpu
>
> Usage:
>     qemu-system-x86_64 -vga virtio [ ... ]
>     qemu-system-x86_64 -device virtio-vga [ ... ]
>     qemu-system-ppc64 -M pseries -device virtio-gpu-pci [ ... ]
>     qemu-system-arm -M virt -device virtio-gpu-device [ ... ]

For what it's worth, I'm done with "reviewing" (except I'm afraid to 
give R-b's here, so I'm sorry my comments where largely (if not 
completely) negative...). It's nice to see things are getting going! :-)

Max

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [Qemu-devel] [RfC PATCH 11/15] virtio-vga: add '-vga virtio' support
  2015-02-24 16:26   ` Marc-André Lureau
@ 2015-02-27  9:27     ` Gerd Hoffmann
  0 siblings, 0 replies; 44+ messages in thread
From: Gerd Hoffmann @ 2015-02-27  9:27 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: Dave Airlie, Michael S. Tsirkin, qemu-devel, Anthony Liguori,
	Paolo Bonzini

  Hi,

>  DEF("vga", HAS_ARG, QEMU_OPTION_vga,
> -    "-vga [std|cirrus|vmware|qxl|xenfb|tcx|cg3|none]\n"
> +    "-vga [std|cirrus|vmware|qxl|xenfb|tcx|cg3|virtio|none]\n"

> +@item virtio
> +Virtio VGA

Fixed.

thanks,
  Gerd

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [Qemu-devel] [RfC PATCH 05/15] virtio-gpu/2d: add hardware spec include file
  2015-02-25 20:04   ` Max Reitz
@ 2015-02-27  9:37     ` Gerd Hoffmann
  0 siblings, 0 replies; 44+ messages in thread
From: Gerd Hoffmann @ 2015-02-27  9:37 UTC (permalink / raw)
  To: Max Reitz; +Cc: Dave Airlie, qemu-devel

On Mi, 2015-02-25 at 15:04 -0500, Max Reitz wrote:
> On 2015-02-23 at 05:23, Gerd Hoffmann wrote:
> > This patch adds the header file with structs and defines for
> > the virtio based gpu device.  Covers 2d operations only.
> >
> > Written by Dave Airlie and Gerd Hoffmann.
> >
> > Signed-off-by: Dave Airlie <airlied@redhat.com>
> > Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> > ---
> >   include/hw/virtio/virtgpu_hw.h | 203 +++++++++++++++++++++++++++++++++++++++++
> >   1 file changed, 203 insertions(+)
> >   create mode 100644 include/hw/virtio/virtgpu_hw.h
> >
> > diff --git a/include/hw/virtio/virtgpu_hw.h b/include/hw/virtio/virtgpu_hw.h
> > new file mode 100644
> > index 0000000..d6641e8
> > --- /dev/null
> > +++ b/include/hw/virtio/virtgpu_hw.h
> > @@ -0,0 +1,203 @@
> > +/*
> > + * Virtio GPU Device
> > + *
> > + * Copyright Red Hat, Inc. 2013-2014
> 
> Hm... Well, if there haven't been any changes since 2014...

The header files hasn't seen any 2015 changes indeed ;)

> > + * 3. Neither the name of IBM nor the names of its contributors
> 
> Is the "IBM" intended?

Looks like cut+paste from virtio_ring.h ...

'IBM' probably comes from rusty being employed by IBM.

> > +struct virtio_gpu_ctrl_hdr {
> > +    uint32_t type;
> > +    uint32_t flags;
> > +    uint64_t fence_id;
> > +    uint32_t ctx_id;
> > +    uint32_t padding;
> > +};
> 
> Shouldn't all these structures be QEMU_PACKED? In practice, it won't 
> matter (I hope!), but if you're relying on it...

It should not indeed, I carefully checked we don't have any funky stuff
in there, like unaligned 64bit fields which have different packing in
i686 and x86_64.

Also the header files is shared between linux and qemu, so adding
QEMU_PACKED there is a bit difficult.

cheers,
  Gerd

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [Qemu-devel] [RfC PATCH 06/15] virtio-gpu/2d: add virtio gpu core code
  2015-02-26 16:08   ` Max Reitz
@ 2015-02-27 11:10     ` Gerd Hoffmann
  2015-02-27 14:20       ` Max Reitz
  2015-03-01 22:03     ` Dave Airlie
  1 sibling, 1 reply; 44+ messages in thread
From: Gerd Hoffmann @ 2015-02-27 11:10 UTC (permalink / raw)
  To: Max Reitz; +Cc: Dave Airlie, qemu-devel, Anthony Liguori, Michael S. Tsirkin

On Do, 2015-02-26 at 11:08 -0500, Max Reitz wrote:
> On 2015-02-23 at 05:23, Gerd Hoffmann wrote:
> > This patch adds the core code for virtio gpu emulation,
> > covering 2d support.
> >
> > Written by Dave Airlie and Gerd Hoffmann.
> >
> > Signed-off-by: Dave Airlie<airlied@redhat.com>
> > Signed-off-by: Gerd Hoffmann<kraxel@redhat.com>
> > ---
> >   hw/display/Makefile.objs       |   2 +
> >   hw/display/virtio-gpu.c        | 903 +++++++++++++++++++++++++++++++++++++++++
> >   include/hw/virtio/virtio-gpu.h | 147 +++++++
> >   trace-events                   |  14 +
> >   4 files changed, 1066 insertions(+)
> >   create mode 100644 hw/display/virtio-gpu.c
> >   create mode 100644 include/hw/virtio/virtio-gpu.h
> 
> Again I mostly only have formal complaints...
> 
> But one non-formal question: As far as I understood virtio-gpu's mode of 
> operation from this patch, it looks like there is one resource per 
> scanout, and that resource is basically the whole screen (which can be 
> updated partially).

This is correct (for 2d mode, 3d will be different).

> If that is the case, what do we gain from being able to display a 
> resource on multiple scanouts? If we don't associate a scanout to a 
> resource with set_scanout, the resource won't ever be displayed on that 
> scanout; and if we associate it, the scanout's position and dimension 
> will be exactly the same as the resource's, so associating a resource 
> with multiple scanouts means that all those scanouts will be duplicates 
> of each other, which in turn means we can duplicate heads. But that 
> seems more like a frontend feature to me...

It's handled this way to mimic behavior of physical hardware, where you
can configure your scanouts (monitor plugs of gfx hardware) in a simliar
way.

Main advantage of taking this route is that virtual hardware and
physical hardware can be configued the same way, i.e. you can -- for
example -- setup screen mirroring with xrandr.

> > +static void update_cursor_data_simple(VirtIOGPU *g,
> > +                                      struct virtio_gpu_scanout *s,
> > +                                      uint32_t resource_id)
> > +{
> > +    struct virtio_gpu_simple_resource *res;
> > +    uint32_t pixels;
> > +
> > +    res = virtio_gpu_find_resource(g, resource_id);
> > +    if (!res) {
> > +        return;
> > +    }
> > +
> > +    pixels = s->current_cursor->width * s->current_cursor->height;
> 
> This multiplication might overflow (but I can't imagine that one could 
> use this for an exploit).

Added checks.

> > +static struct virtio_gpu_simple_resource *
> > +virtio_gpu_find_resource(VirtIOGPU *g, uint32_t resource_id)
> > +{
> > +    struct virtio_gpu_simple_resource *res;
> > +
> > +    QTAILQ_FOREACH(res, &g->reslist, next) {
> > +        if (res->resource_id == resource_id) {
> > +            return res;
> > +        }
> > +    }
> > +    return NULL;
> > +}
> 
> How often do you think this function is called, and how many resources 
> do you expect there to be? Would it make sense to make this a hash table?

Not for 2d, it's only scanouts and cursors.

In 3d mode virglrenderer will manage resources, and there will be alot
more (textures, buffers, ....).

> > +        cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
> > +        return;
> > +    }
> > +
> > +    res = g_new0(struct virtio_gpu_simple_resource, 1);
> > +
> > +    res->width = c2d.width;
> > +    res->height = c2d.height;
> > +    res->format = c2d.format;
> > +    res->resource_id = c2d.resource_id;
> 
> Considering resource_id == 0 is sometimes (apparently) used as "no 
> resource" (e.g. in transfer_to_host_2d), would it make sense to test 
> against that here?

Added check.

> > +    format = pixman_image_get_format(res->image);
> > +    bpp = (PIXMAN_FORMAT_BPP(format) + 7) / 8;
> 
> Could have used DIV_ROUND_UP(); also, I don't find it anywhere in the 
> virtio-gpu spec (at least not in the one spec I found), so will this 
> really work if PIXMAN_FORMAT_BPP(format) is not a multiple of 8? I can 
> imagine this being correct for *_BPP() == 15, but maybe not so much for 
> *_BPP() == 1; but then again, maybe you don't plan on supporting 
> sub-byte pixel formats anyway.

Yes, it's for bpp=15.

> > +    if (t2d.offset || t2d.r.x || t2d.r.y ||
> > +        t2d.r.width != pixman_image_get_width(res->image)) {
> > +        void *img_data = pixman_image_get_data(res->image);
> > +        for (h = 0; h < t2d.r.height; h++) {
> > +            src_offset = t2d.offset + stride * h;
> > +            dst_offset = (t2d.r.y + h) * stride + (t2d.r.x * bpp);
> > +
> > +            iov_to_buf(res->iov, res->iov_cnt, src_offset,
> > +                       (uint8_t *)img_data
> > +                       + dst_offset, t2d.r.width * bpp);
> > +        }
> > +    } else {
> > +        iov_to_buf(res->iov, res->iov_cnt, 0,
> > +                   pixman_image_get_data(res->image),
> > +                   pixman_image_get_stride(res->image)
> > +                   * pixman_image_get_height(res->image));
> 
> Will this work with stride != t2d.r.width * bpp?

Those cases should take the if branch above and loop over all lines to
handle it correctly.

> > +    res = virtio_gpu_find_resource(g, ss.resource_id);
> 
> If ss.resource_id == 0, the result is unused; this function call could 
> therefore be put after the next if block.

Done.

> > +    g->enable = 1;
> > +    if (ss.resource_id == 0) {
> > +        scanout = &g->scanout[ss.scanout_id];
> > +        if (g->scanout[ss.scanout_id].resource_id) {
> 
> Would be shorter as "if (scanout->resource_id)".

Yep, fixed.

> > +int virtio_gpu_create_mapping_iov(struct virtio_gpu_resource_attach_backing *ab,
> > +                                  struct virtio_gpu_ctrl_command *cmd,
> > +                                  struct iovec **iov)
> > +{
> > +    struct virtio_gpu_mem_entry *ents;
> > +    size_t esize, s;
> > +    int i;
> > +
> > +    esize = sizeof(*ents) * ab->nr_entries;
> 
> Can overflow (on 32 bit hosts).

[ ... ]

> However, I think it's best to simply limit ab->nr_entries to some sane 
> value

Done.

thanks,
  Gerd

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [Qemu-devel] [RfC PATCH 07/15] virtio-gpu-pci: add virtio pci support
  2015-02-26 16:25   ` Max Reitz
@ 2015-02-27 11:13     ` Gerd Hoffmann
  0 siblings, 0 replies; 44+ messages in thread
From: Gerd Hoffmann @ 2015-02-27 11:13 UTC (permalink / raw)
  To: Max Reitz; +Cc: Dave Airlie, qemu-devel, Anthony Liguori, Michael S. Tsirkin

> > diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h
> > index bdee464..4a18ef5 100644
> > --- a/include/hw/pci/pci.h
> > +++ b/include/hw/pci/pci.h
> > @@ -81,6 +81,7 @@
> >   #define PCI_DEVICE_ID_VIRTIO_SCSI        0x1004
> >   #define PCI_DEVICE_ID_VIRTIO_RNG         0x1005
> >   #define PCI_DEVICE_ID_VIRTIO_9P          0x1009
> > +#define PCI_DEVICE_ID_VIRTIO_GPU         0x1010
> >   
> >   #define PCI_VENDOR_ID_REDHAT             0x1b36
> >   #define PCI_DEVICE_ID_REDHAT_BRIDGE      0x0001

Dropped, not used.

cheers,
  Gerd

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [Qemu-devel] [RfC PATCH 01/15] virtio-pci: add flags to enable/disable legacy/modern
  2015-02-26 16:41   ` Max Reitz
@ 2015-02-27 11:15     ` Gerd Hoffmann
  2015-02-27 14:20       ` Max Reitz
  0 siblings, 1 reply; 44+ messages in thread
From: Gerd Hoffmann @ 2015-02-27 11:15 UTC (permalink / raw)
  To: Max Reitz; +Cc: qemu-devel, Anthony Liguori, Michael S. Tsirkin

> Hm, the virtio 1.0 specification from December 2013 states (4.1.1 PCI 
> Device Discovery):

Outdated draft, look here for the final specs:

http://docs.oasis-open.org/virtio/virtio/v1.0/

cheers,
  Gerd

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [Qemu-devel] [RfC PATCH 08/15] virtio-gpu-pci: virtio-1.0 adaptions [fixup]
  2015-02-26 16:46   ` Max Reitz
@ 2015-02-27 11:18     ` Gerd Hoffmann
  2015-02-27 14:30       ` Max Reitz
  0 siblings, 1 reply; 44+ messages in thread
From: Gerd Hoffmann @ 2015-02-27 11:18 UTC (permalink / raw)
  To: Max Reitz; +Cc: qemu-devel, Anthony Liguori, Michael S. Tsirkin

  Hi,

> This seems to be in line with the changes made in patch 1; however, I 
> fail to see where VirtIODevice.device_id is set so that 
> virtio_bus_get_vdev_id() returns it when called from 
> virtio_pci_device_plugged()... Maybe I'll find it yet.

virtio_gpu_device_realize() calls virtio_init() with the id as one of
the parameters.

cheers,
  Gerd

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [Qemu-devel] [RfC PATCH 12/15] virtio-vga: add vgabios configuration
  2015-02-26 18:13   ` Max Reitz
@ 2015-02-27 11:25     ` Gerd Hoffmann
  0 siblings, 0 replies; 44+ messages in thread
From: Gerd Hoffmann @ 2015-02-27 11:25 UTC (permalink / raw)
  To: Max Reitz; +Cc: qemu-devel

> > +CONFIG_OVERRIDE_PCI_ID=y
> > +CONFIG_VGA_VID=0x1af4
> > +CONFIG_VGA_DID=0x1010
> 
> Will this device ID work, even with your fixups regarding the PCI device ID?

Needs updating for virtio-1.0 indeed.

Seems to not cause problems though for some strange reason, didn't trip
up in testing so far ...

fixed,
  Gerd

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [Qemu-devel] [RfC PATCH 00/15] virtio-gpu:
  2015-02-26 18:40 ` [Qemu-devel] [RfC PATCH 00/15] virtio-gpu: Max Reitz
@ 2015-02-27 11:30   ` Gerd Hoffmann
  0 siblings, 0 replies; 44+ messages in thread
From: Gerd Hoffmann @ 2015-02-27 11:30 UTC (permalink / raw)
  To: Max Reitz; +Cc: qemu-devel

  Hi,

> For what it's worth, I'm done with "reviewing" (except I'm afraid to 
> give R-b's here, so I'm sorry my comments where largely (if not 
> completely) negative...). It's nice to see things are getting going! :-)

Naa, all fine here.  You've found some real issues, and this is exactly
what review is good for.  And finding problems tends to be negative by
principle, so no worries.

thanks,
  Gerd

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [Qemu-devel] [RfC PATCH 06/15] virtio-gpu/2d: add virtio gpu core code
  2015-02-27 11:10     ` Gerd Hoffmann
@ 2015-02-27 14:20       ` Max Reitz
  2015-02-27 14:31         ` Gerd Hoffmann
  0 siblings, 1 reply; 44+ messages in thread
From: Max Reitz @ 2015-02-27 14:20 UTC (permalink / raw)
  To: Gerd Hoffmann
  Cc: Dave Airlie, qemu-devel, Anthony Liguori, Michael S. Tsirkin

On 2015-02-27 at 06:10, Gerd Hoffmann wrote:
> On Do, 2015-02-26 at 11:08 -0500, Max Reitz wrote:
>> On 2015-02-23 at 05:23, Gerd Hoffmann wrote:
>>> This patch adds the core code for virtio gpu emulation,
>>> covering 2d support.
>>>
>>> Written by Dave Airlie and Gerd Hoffmann.
>>>
>>> Signed-off-by: Dave Airlie<airlied@redhat.com>
>>> Signed-off-by: Gerd Hoffmann<kraxel@redhat.com>
>>> ---
>>>    hw/display/Makefile.objs       |   2 +
>>>    hw/display/virtio-gpu.c        | 903 +++++++++++++++++++++++++++++++++++++++++
>>>    include/hw/virtio/virtio-gpu.h | 147 +++++++
>>>    trace-events                   |  14 +
>>>    4 files changed, 1066 insertions(+)
>>>    create mode 100644 hw/display/virtio-gpu.c
>>>    create mode 100644 include/hw/virtio/virtio-gpu.h
>> Again I mostly only have formal complaints...
>>
>> But one non-formal question: As far as I understood virtio-gpu's mode of
>> operation from this patch, it looks like there is one resource per
>> scanout, and that resource is basically the whole screen (which can be
>> updated partially).
> This is correct (for 2d mode, 3d will be different).
>
>> If that is the case, what do we gain from being able to display a
>> resource on multiple scanouts? If we don't associate a scanout to a
>> resource with set_scanout, the resource won't ever be displayed on that
>> scanout; and if we associate it, the scanout's position and dimension
>> will be exactly the same as the resource's, so associating a resource
>> with multiple scanouts means that all those scanouts will be duplicates
>> of each other, which in turn means we can duplicate heads. But that
>> seems more like a frontend feature to me...
> It's handled this way to mimic behavior of physical hardware, where you
> can configure your scanouts (monitor plugs of gfx hardware) in a simliar
> way.
>
> Main advantage of taking this route is that virtual hardware and
> physical hardware can be configued the same way, i.e. you can -- for
> example -- setup screen mirroring with xrandr.

OK.

[snip]

>>> +    if (t2d.offset || t2d.r.x || t2d.r.y ||
>>> +        t2d.r.width != pixman_image_get_width(res->image)) {
>>> +        void *img_data = pixman_image_get_data(res->image);
>>> +        for (h = 0; h < t2d.r.height; h++) {
>>> +            src_offset = t2d.offset + stride * h;
>>> +            dst_offset = (t2d.r.y + h) * stride + (t2d.r.x * bpp);
>>> +
>>> +            iov_to_buf(res->iov, res->iov_cnt, src_offset,
>>> +                       (uint8_t *)img_data
>>> +                       + dst_offset, t2d.r.width * bpp);
>>> +        }
>>> +    } else {
>>> +        iov_to_buf(res->iov, res->iov_cnt, 0,
>>> +                   pixman_image_get_data(res->image),
>>> +                   pixman_image_get_stride(res->image)
>>> +                   * pixman_image_get_height(res->image));
>> Will this work with stride != t2d.r.width * bpp?
> Those cases should take the if branch above and loop over all lines to
> handle it correctly.

Exactly, but it looks like to me that it doesn't (at least not always).

Max

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [Qemu-devel] [RfC PATCH 01/15] virtio-pci: add flags to enable/disable legacy/modern
  2015-02-27 11:15     ` Gerd Hoffmann
@ 2015-02-27 14:20       ` Max Reitz
  0 siblings, 0 replies; 44+ messages in thread
From: Max Reitz @ 2015-02-27 14:20 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: qemu-devel, Anthony Liguori, Michael S. Tsirkin

On 2015-02-27 at 06:15, Gerd Hoffmann wrote:
>> Hm, the virtio 1.0 specification from December 2013 states (4.1.1 PCI
>> Device Discovery):
> Outdated draft, look here for the final specs:
>
> http://docs.oasis-open.org/virtio/virtio/v1.0/

Thanks!

Max

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [Qemu-devel] [RfC PATCH 08/15] virtio-gpu-pci: virtio-1.0 adaptions [fixup]
  2015-02-27 11:18     ` Gerd Hoffmann
@ 2015-02-27 14:30       ` Max Reitz
  0 siblings, 0 replies; 44+ messages in thread
From: Max Reitz @ 2015-02-27 14:30 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: qemu-devel, Anthony Liguori, Michael S. Tsirkin

On 2015-02-27 at 06:18, Gerd Hoffmann wrote:
>    Hi,
>
>> This seems to be in line with the changes made in patch 1; however, I
>> fail to see where VirtIODevice.device_id is set so that
>> virtio_bus_get_vdev_id() returns it when called from
>> virtio_pci_device_plugged()... Maybe I'll find it yet.
> virtio_gpu_device_realize() calls virtio_init() with the id as one of
> the parameters.

Right. Thanks!

Max

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [Qemu-devel] [RfC PATCH 06/15] virtio-gpu/2d: add virtio gpu core code
  2015-02-27 14:20       ` Max Reitz
@ 2015-02-27 14:31         ` Gerd Hoffmann
  2015-02-27 14:33           ` Max Reitz
  0 siblings, 1 reply; 44+ messages in thread
From: Gerd Hoffmann @ 2015-02-27 14:31 UTC (permalink / raw)
  To: Max Reitz; +Cc: Dave Airlie, qemu-devel, Anthony Liguori, Michael S. Tsirkin

> >>> +    if (t2d.offset || t2d.r.x || t2d.r.y ||
> >>> +        t2d.r.width != pixman_image_get_width(res->image)) {

> >> Will this work with stride != t2d.r.width * bpp?
> > Those cases should take the if branch above and loop over all lines to
> > handle it correctly.
> 
> Exactly, but it looks like to me that it doesn't (at least not always).

Ah, you mean we should better check something like

  t2d.r.width * bpp != pixman_image_get_stride() ?

That should check exactly the same thing as we never create resources
with extra padding where width * bpp != stride.

cheers,
  Gerd

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [Qemu-devel] [RfC PATCH 06/15] virtio-gpu/2d: add virtio gpu core code
  2015-02-27 14:31         ` Gerd Hoffmann
@ 2015-02-27 14:33           ` Max Reitz
  0 siblings, 0 replies; 44+ messages in thread
From: Max Reitz @ 2015-02-27 14:33 UTC (permalink / raw)
  To: Gerd Hoffmann
  Cc: Dave Airlie, qemu-devel, Anthony Liguori, Michael S. Tsirkin

On 2015-02-27 at 09:31, Gerd Hoffmann wrote:
>>>>> +    if (t2d.offset || t2d.r.x || t2d.r.y ||
>>>>> +        t2d.r.width != pixman_image_get_width(res->image)) {
>>>> Will this work with stride != t2d.r.width * bpp?
>>> Those cases should take the if branch above and loop over all lines to
>>> handle it correctly.
>> Exactly, but it looks like to me that it doesn't (at least not always).
> Ah, you mean we should better check something like
>
>    t2d.r.width * bpp != pixman_image_get_stride() ?
>
> That should check exactly the same thing as we never create resources
> with extra padding where width * bpp != stride.

Ah, you're right, I missed that. Very well then.

Max

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [Qemu-devel] [RfC PATCH 06/15] virtio-gpu/2d: add virtio gpu core code
  2015-02-26 16:08   ` Max Reitz
  2015-02-27 11:10     ` Gerd Hoffmann
@ 2015-03-01 22:03     ` Dave Airlie
  2015-03-02 12:57       ` Gerd Hoffmann
  1 sibling, 1 reply; 44+ messages in thread
From: Dave Airlie @ 2015-03-01 22:03 UTC (permalink / raw)
  To: Max Reitz
  Cc: Dave Airlie, Michael S. Tsirkin, Gerd Hoffmann, Anthony Liguori,
	qemu-devel

>
> But one non-formal question: As far as I understood virtio-gpu's mode of
> operation from this patch, it looks like there is one resource per scanout,
> and that resource is basically the whole screen (which can be updated
> partially).
>
> If that is the case, what do we gain from being able to display a resource
> on multiple scanouts? If we don't associate a scanout to a resource with
> set_scanout, the resource won't ever be displayed on that scanout; and if we
> associate it, the scanout's position and dimension will be exactly the same
> as the resource's, so associating a resource with multiple scanouts means
> that all those scanouts will be duplicates of each other, which in turn
> means we can duplicate heads. But that seems more like a frontend feature to
> me...

Just how real hw works, and sw expects it, we have resources, and
multiple scanouts
can access one resource, or each scanout can have its own private resource.
> too).
>
>> +        cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
>> +        return;
>> +    }
>> +
>> +    res = g_new0(struct virtio_gpu_simple_resource, 1);
>> +
>> +    res->width = c2d.width;
>> +    res->height = c2d.height;
>> +    res->format = c2d.format;
>> +    res->resource_id = c2d.resource_id;
>
>
> Considering resource_id == 0 is sometimes (apparently) used as "no resource"
> (e.g. in transfer_to_host_2d), would it make sense to test against that
> here?

Gerd, btw I think we mighr want to support a set scanout with no
resource, as it might make Linux atomic modesetting easier in the
future, we'd just scanout black.

>> +                                  struct iovec **iov)
>> +{
>> +    struct virtio_gpu_mem_entry *ents;
>> +    size_t esize, s;
>> +    int i;
>> +
>> +    esize = sizeof(*ents) * ab->nr_entries;
>
>
> Can overflow (on 32 bit hosts).
>
> (And this might be bad, because this function works just fine, and then
> either the for loop does something, or nr_entries is negative when casted to
> signed int, and then the for loop won't do anything; but res->iov_cnt
> (unsigned int) will be set to ab->nr_entries, so this may or may not be
> exploitable, but can probably lead to a crash)
>
>> +    ents = g_malloc(esize);
>
>
> And this may need to be g_try_malloc().
>
> However, I think it's best to simply limit ab->nr_entries to some sane value
> (I guess it shouldn't be even in the double digits for a single resource, so
> restricting it to 256 or something seems sane to me...) and return an error
> to the guest if that limit is exceeded.

please be careful about limiting this, limits should be pessimistic, as if the
the GPU allocates one page per iov, so a 1280x1024x32bpp resource will
have 1280 iovs.

Dave.

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [Qemu-devel] [RfC PATCH 03/15] virtio-pci: make pci bars configurable
  2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 03/15] virtio-pci: make pci bars configurable Gerd Hoffmann
@ 2015-03-02 12:30   ` Michael S. Tsirkin
  2015-03-02 13:10     ` Gerd Hoffmann
  0 siblings, 1 reply; 44+ messages in thread
From: Michael S. Tsirkin @ 2015-03-02 12:30 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: qemu-devel

On Mon, Feb 23, 2015 at 11:23:19AM +0100, Gerd Hoffmann wrote:
> Add msix_bar and modern_mem_bar fields to VirtIOPCIProxy.  They can be
> used to configure which pci regions are used for the virtio 1.0 memory
> bar and the msix bar.
> 
> For legacy/transitional devices the legacy bar is region 0 and the msix
> bar is region 1.  Only the modern bar can be configured, and it must be
> 2 or larger.  Default is 2.
> 
> For legacy-free devices the modern bar is region 0 by default and the
> msix bar is 2 by default.
> 
> Use case: For VirtIOPCIProxy subclasses which need additional pci bars,
> such as virtio-vga.  With the new fields they can make sure the regions
> do not conflict.
> 
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>

Hmm, I'd rather add an API to register a free BAR.
What's wrong with that?

> ---
>  hw/virtio/virtio-pci.c | 25 +++++++++++++++++++++----
>  hw/virtio/virtio-pci.h |  2 ++
>  2 files changed, 23 insertions(+), 4 deletions(-)
> 
> diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
> index cd7c777..f97baf2 100644
> --- a/hw/virtio/virtio-pci.c
> +++ b/hw/virtio/virtio-pci.c
> @@ -965,8 +965,6 @@ static void virtio_pci_add_mem_cap(VirtIOPCIProxy *proxy,
>      PCIDevice *dev = &proxy->pci_dev;
>      int offset;
>  
> -    cap->bar = 2;
> -
>      offset = pci_add_capability(dev, PCI_CAP_ID_VNDR, 0, cap->cap_len);
>      assert(offset > 0);
>  
> @@ -1243,11 +1241,21 @@ static void virtio_pci_device_plugged(DeviceState *d)
>          pci_config_set_class(config, proxy->class_code);
>      }
>  
> +    if (proxy->modern_mem_bar > 5) {
> +        proxy->modern_mem_bar = 5;
> +    }
> +    if (proxy->msix_bar > 5) {
> +        proxy->msix_bar = 5;
> +    }
>      if (legacy) {
>          /* legacy and transitional */
>          pci_set_word(config + PCI_SUBSYSTEM_VENDOR_ID,
>                       pci_get_word(config + PCI_VENDOR_ID));
>          pci_set_word(config + PCI_SUBSYSTEM_ID, virtio_bus_get_vdev_id(bus));
> +        proxy->msix_bar = 1;
> +        if (proxy->modern_mem_bar < 2) {
> +            proxy->modern_mem_bar = 2;
> +        }
>      } else {
>          /* pure virtio-1.0 */
>          pci_set_word(config + PCI_VENDOR_ID,
> @@ -1255,6 +1263,9 @@ static void virtio_pci_device_plugged(DeviceState *d)
>          pci_set_word(config + PCI_DEVICE_ID,
>                       0x1040 + virtio_bus_get_vdev_id(bus));
>          pci_config_set_revision(config, 1);
> +        if (proxy->msix_bar == proxy->modern_mem_bar) {
> +            proxy->msix_bar = (proxy->msix_bar + 2) % 6;
> +        }
>      }
>      config[PCI_INTERRUPT_PIN] = 1;
>  
> @@ -1263,24 +1274,28 @@ static void virtio_pci_device_plugged(DeviceState *d)
>          struct virtio_pci_cap common = {
>              .cfg_type = VIRTIO_PCI_CAP_COMMON_CFG,
>              .cap_len = sizeof common,
> +            .bar = proxy->modern_mem_bar,
>              .offset = cpu_to_le32(0x0),
>              .length = cpu_to_le32(0x1000),
>          };
>          struct virtio_pci_cap isr = {
>              .cfg_type = VIRTIO_PCI_CAP_ISR_CFG,
>              .cap_len = sizeof isr,
> +            .bar = proxy->modern_mem_bar,
>              .offset = cpu_to_le32(0x1000),
>              .length = cpu_to_le32(0x1000),
>          };
>          struct virtio_pci_cap device = {
>              .cfg_type = VIRTIO_PCI_CAP_DEVICE_CFG,
>              .cap_len = sizeof device,
> +            .bar = proxy->modern_mem_bar,
>              .offset = cpu_to_le32(0x2000),
>              .length = cpu_to_le32(0x1000),
>          };
>          struct virtio_pci_notify_cap notify = {
>              .cap.cfg_type = VIRTIO_PCI_CAP_NOTIFY_CFG,
>              .cap.cap_len = sizeof notify,
> +            .cap.bar = proxy->modern_mem_bar,
>              .cap.offset = cpu_to_le32(0x3000),
>              .cap.length = cpu_to_le32(QEMU_VIRTIO_PCI_QUEUE_MEM_MULT *
>                                        VIRTIO_PCI_QUEUE_MAX),
> @@ -1359,12 +1374,14 @@ static void virtio_pci_device_plugged(DeviceState *d)
>                                QEMU_VIRTIO_PCI_QUEUE_MEM_MULT *
>                                VIRTIO_PCI_QUEUE_MAX);
>          memory_region_add_subregion(&proxy->modern_bar, 0x3000, &proxy->notify);
> -        pci_register_bar(&proxy->pci_dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY,
> +        pci_register_bar(&proxy->pci_dev, proxy->modern_mem_bar,
> +                         PCI_BASE_ADDRESS_SPACE_MEMORY,
>                           &proxy->modern_bar);
>      }
>  
>      if (proxy->nvectors &&
> -        msix_init_exclusive_bar(&proxy->pci_dev, proxy->nvectors, 1)) {
> +        msix_init_exclusive_bar(&proxy->pci_dev, proxy->nvectors,
> +                                proxy->msix_bar)) {
>          error_report("unable to init msix vectors to %" PRIu32,
>                       proxy->nvectors);
>          proxy->nvectors = 0;
> diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h
> index 3068a63..a273c33 100644
> --- a/hw/virtio/virtio-pci.h
> +++ b/hw/virtio/virtio-pci.h
> @@ -102,6 +102,8 @@ struct VirtIOPCIProxy {
>      uint32_t flags;
>      uint32_t class_code;
>      uint32_t nvectors;
> +    uint32_t msix_bar;
> +    uint32_t modern_mem_bar;
>      uint64_t host_features;
>      uint32_t dfselect;
>      uint32_t gfselect;
> -- 
> 1.8.3.1

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [Qemu-devel] [RfC PATCH 04/15] virtio-pci: make modern bar 64bit prefetchable
  2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 04/15] virtio-pci: make modern bar 64bit prefetchable Gerd Hoffmann
@ 2015-03-02 12:33   ` Michael S. Tsirkin
  0 siblings, 0 replies; 44+ messages in thread
From: Michael S. Tsirkin @ 2015-03-02 12:33 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: qemu-devel, Anthony Liguori

On Mon, Feb 23, 2015 at 11:23:20AM +0100, Gerd Hoffmann wrote:
> Modern bar is made prefetchable.  In case it is configured to use one of
> the bars 0, 2, or 4 (which by default is the case) it is also configured
> as 64bit region.
> 
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>

Fine, but I can't apply this without 3/15.

> ---
>  hw/virtio/virtio-pci.c | 12 +++++++++---
>  1 file changed, 9 insertions(+), 3 deletions(-)
> 
> diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
> index f97baf2..96b3692 100644
> --- a/hw/virtio/virtio-pci.c
> +++ b/hw/virtio/virtio-pci.c
> @@ -1263,7 +1263,8 @@ static void virtio_pci_device_plugged(DeviceState *d)
>          pci_set_word(config + PCI_DEVICE_ID,
>                       0x1040 + virtio_bus_get_vdev_id(bus));
>          pci_config_set_revision(config, 1);
> -        if (proxy->msix_bar == proxy->modern_mem_bar) {
> +        if ((proxy->msix_bar == proxy->modern_mem_bar) ||
> +            (proxy->msix_bar == proxy->modern_mem_bar+1)) {
>              proxy->msix_bar = (proxy->msix_bar + 2) % 6;
>          }
>      }

I'd like to avoid extra (), and see space around +.
E.g.
        if (proxy->msix_bar == proxy->modern_mem_bar ||
            proxy->msix_bar == proxy->modern_mem_bar + 1)

we can generally rely on C to DTRT wrt priority of arithmentic
operations and comparisons.

> @@ -1301,6 +1302,7 @@ static void virtio_pci_device_plugged(DeviceState *d)
>                                        VIRTIO_PCI_QUEUE_MAX),
>              .notify_off_multiplier = cpu_to_le32(QEMU_VIRTIO_PCI_QUEUE_MEM_MULT),
>          };
> +        uint32_t modern_mem_attr;
>  
>          static const MemoryRegionOps common_ops = {
>              .read = virtio_pci_common_read,
> @@ -1374,9 +1376,13 @@ static void virtio_pci_device_plugged(DeviceState *d)
>                                QEMU_VIRTIO_PCI_QUEUE_MEM_MULT *
>                                VIRTIO_PCI_QUEUE_MAX);
>          memory_region_add_subregion(&proxy->modern_bar, 0x3000, &proxy->notify);
> +        modern_mem_attr = (PCI_BASE_ADDRESS_SPACE_MEMORY |
> +                           PCI_BASE_ADDRESS_MEM_PREFETCH);

no need for () to the right of =.

> +        if (!(proxy->modern_mem_bar % 2)) {
> +            modern_mem_attr |= PCI_BASE_ADDRESS_MEM_TYPE_64;
> +        }

That's pretty unexpected.
This kind of hack seems to show why it's not a good idea
to let device play with layouts.

>          pci_register_bar(&proxy->pci_dev, proxy->modern_mem_bar,
> -                         PCI_BASE_ADDRESS_SPACE_MEMORY,
> -                         &proxy->modern_bar);
> +                         modern_mem_attr, &proxy->modern_bar);
>      }
>  
>      if (proxy->nvectors &&
> -- 
> 1.8.3.1

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [Qemu-devel] [RfC PATCH 01/15] virtio-pci: add flags to enable/disable legacy/modern
  2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 01/15] virtio-pci: add flags to enable/disable legacy/modern Gerd Hoffmann
  2015-02-26 16:41   ` Max Reitz
@ 2015-03-02 12:34   ` Michael S. Tsirkin
  2015-03-02 13:25     ` Gerd Hoffmann
  1 sibling, 1 reply; 44+ messages in thread
From: Michael S. Tsirkin @ 2015-03-02 12:34 UTC (permalink / raw)
  To: Gerd Hoffmann; +Cc: qemu-devel, Anthony Liguori

On Mon, Feb 23, 2015 at 11:23:17AM +0100, Gerd Hoffmann wrote:
> Add VIRTIO_PCI_FLAG_DISABLE_LEGACY and VIRTIO_PCI_FLAG_DISABLE_MODERN
> for VirtIOPCIProxy->flags.  Also add properties for them.  They can be
> used to disable modern (virtio 1.0) or legacy (virtio 0.9) modes.  By
> default both are advertized and the guest driver can choose.
> 
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>

I merged patches 1 and 2. I'm guessing you don't want gpu merged yet?

> ---
>  hw/virtio/virtio-pci.c | 46 +++++++++++++++++++++++++++++++++-------------
>  hw/virtio/virtio-pci.h |  6 ++++++
>  2 files changed, 39 insertions(+), 13 deletions(-)
> 
> diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
> index 4c9a0b8..6c0c650 100644
> --- a/hw/virtio/virtio-pci.c
> +++ b/hw/virtio/virtio-pci.c
> @@ -1233,6 +1233,8 @@ static void virtio_pci_device_plugged(DeviceState *d)
>  {
>      VirtIOPCIProxy *proxy = VIRTIO_PCI(d);
>      VirtioBusState *bus = &proxy->bus;
> +    bool legacy = !(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_LEGACY);
> +    bool modern = !(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_MODERN);
>      uint8_t *config;
>      uint32_t size;
>  
> @@ -1240,13 +1242,24 @@ static void virtio_pci_device_plugged(DeviceState *d)
>      if (proxy->class_code) {
>          pci_config_set_class(config, proxy->class_code);
>      }
> -    pci_set_word(config + PCI_SUBSYSTEM_VENDOR_ID,
> -                 pci_get_word(config + PCI_VENDOR_ID));
> -    pci_set_word(config + PCI_SUBSYSTEM_ID, virtio_bus_get_vdev_id(bus));
> +
> +    if (legacy) {
> +        /* legacy and transitional */
> +        pci_set_word(config + PCI_SUBSYSTEM_VENDOR_ID,
> +                     pci_get_word(config + PCI_VENDOR_ID));
> +        pci_set_word(config + PCI_SUBSYSTEM_ID, virtio_bus_get_vdev_id(bus));
> +    } else {
> +        /* pure virtio-1.0 */
> +        pci_set_word(config + PCI_VENDOR_ID,
> +                     PCI_VENDOR_ID_REDHAT_QUMRANET);
> +        pci_set_word(config + PCI_DEVICE_ID,
> +                     0x1040 + virtio_bus_get_vdev_id(bus));
> +        pci_config_set_revision(config, 1);
> +    }
>      config[PCI_INTERRUPT_PIN] = 1;
>  
>  
> -    if (1) { /* TODO: Make this optional, dependent on virtio 1.0 */
> +    if (modern) {
>          struct virtio_pci_cap common = {
>              .cfg_type = VIRTIO_PCI_CAP_COMMON_CFG,
>              .cap_len = sizeof common,
> @@ -1359,17 +1372,20 @@ static void virtio_pci_device_plugged(DeviceState *d)
>  
>      proxy->pci_dev.config_write = virtio_write_config;
>  
> -    size = VIRTIO_PCI_REGION_SIZE(&proxy->pci_dev)
> -         + virtio_bus_get_vdev_config_len(bus);
> -    if (size & (size - 1)) {
> -        size = 1 << qemu_fls(size);
> -    }
> +    if (legacy) {
> +        size = VIRTIO_PCI_REGION_SIZE(&proxy->pci_dev)
> +            + virtio_bus_get_vdev_config_len(bus);
> +        if (size & (size - 1)) {
> +            size = 1 << qemu_fls(size);
> +        }
>  
> -    memory_region_init_io(&proxy->bar, OBJECT(proxy), &virtio_pci_config_ops,
> -                          proxy, "virtio-pci", size);
> +        memory_region_init_io(&proxy->bar, OBJECT(proxy),
> +                              &virtio_pci_config_ops,
> +                              proxy, "virtio-pci", size);
>  
> -    pci_register_bar(&proxy->pci_dev, 0, PCI_BASE_ADDRESS_SPACE_IO,
> -                     &proxy->bar);
> +        pci_register_bar(&proxy->pci_dev, 0, PCI_BASE_ADDRESS_SPACE_IO,
> +                         &proxy->bar);
> +    }
>  
>      if (!kvm_has_many_ioeventfds()) {
>          proxy->flags &= ~VIRTIO_PCI_FLAG_USE_IOEVENTFD;
> @@ -1416,6 +1432,10 @@ static void virtio_pci_reset(DeviceState *qdev)
>  static Property virtio_pci_properties[] = {
>      DEFINE_PROP_BIT("virtio-pci-bus-master-bug-migration", VirtIOPCIProxy, flags,
>                      VIRTIO_PCI_FLAG_BUS_MASTER_BUG_MIGRATION_BIT, false),
> +    DEFINE_PROP_BIT("disable-legacy", VirtIOPCIProxy, flags,
> +                    VIRTIO_PCI_FLAG_DISABLE_LEGACY_BIT, false),
> +    DEFINE_PROP_BIT("disable-modern", VirtIOPCIProxy, flags,
> +                    VIRTIO_PCI_FLAG_DISABLE_MODERN_BIT, false),
>      DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features),
>      DEFINE_PROP_END_OF_LIST(),
>  };
> diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h
> index 2cddd6a..3068a63 100644
> --- a/hw/virtio/virtio-pci.h
> +++ b/hw/virtio/virtio-pci.h
> @@ -63,6 +63,12 @@ typedef struct VirtioBusClass VirtioPCIBusClass;
>  #define VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT 1
>  #define VIRTIO_PCI_FLAG_USE_IOEVENTFD   (1 << VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT)
>  
> +/* virtio version flags */
> +#define VIRTIO_PCI_FLAG_DISABLE_LEGACY_BIT 2
> +#define VIRTIO_PCI_FLAG_DISABLE_MODERN_BIT 3
> +#define VIRTIO_PCI_FLAG_DISABLE_LEGACY (1 << VIRTIO_PCI_FLAG_DISABLE_LEGACY_BIT)
> +#define VIRTIO_PCI_FLAG_DISABLE_MODERN (1 << VIRTIO_PCI_FLAG_DISABLE_MODERN_BIT)
> +
>  typedef struct {
>      MSIMessage msg;
>      int virq;
> -- 
> 1.8.3.1

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [Qemu-devel] [RfC PATCH 06/15] virtio-gpu/2d: add virtio gpu core code
  2015-03-01 22:03     ` Dave Airlie
@ 2015-03-02 12:57       ` Gerd Hoffmann
  0 siblings, 0 replies; 44+ messages in thread
From: Gerd Hoffmann @ 2015-03-02 12:57 UTC (permalink / raw)
  To: Dave Airlie
  Cc: Dave Airlie, Michael S. Tsirkin, qemu-devel, Anthony Liguori, Max Reitz

  Hi,

> Gerd, btw I think we mighr want to support a set scanout with no
> resource, as it might make Linux atomic modesetting easier in the
> future, we'd just scanout black.

Makes sense, and should be easy to implement.

> > However, I think it's best to simply limit ab->nr_entries to some sane value
> > (I guess it shouldn't be even in the double digits for a single resource, so
> > restricting it to 256 or something seems sane to me...) and return an error
> > to the guest if that limit is exceeded.
> 
> please be careful about limiting this, limits should be pessimistic, as if the
> the GPU allocates one page per iov, so a 1280x1024x32bpp resource will
> have 1280 iovs.

I've already picked 1024 as 256 looked a bit low to me.  Guess we should
better go for 16k instead, that is enough even for ultra hd ...

cheers,
  Gerd

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [Qemu-devel] [RfC PATCH 03/15] virtio-pci: make pci bars configurable
  2015-03-02 12:30   ` Michael S. Tsirkin
@ 2015-03-02 13:10     ` Gerd Hoffmann
  0 siblings, 0 replies; 44+ messages in thread
From: Gerd Hoffmann @ 2015-03-02 13:10 UTC (permalink / raw)
  To: Michael S. Tsirkin; +Cc: qemu-devel

  Hi,

> > Use case: For VirtIOPCIProxy subclasses which need additional pci bars,
> > such as virtio-vga.  With the new fields they can make sure the regions
> > do not conflict.
> > 
> > Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> 
> Hmm, I'd rather add an API to register a free BAR.
> What's wrong with that?

I want a fixed bar (for the legacy vga framebuffer), because that makes
things easier for vgabios etc.  Currently virtio-vga uses bar #2, and
I'd much prefer to not change that as support for this is in seabios
already.

I don't mind much how that is actually implemented though.  Reserving
bar #2 somehow, then have virtio_pci_device_plugged check this and place
the bars automatically in a non-conflicting way is fine with me too.

cheers,
  Gerd

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [Qemu-devel] [RfC PATCH 01/15] virtio-pci: add flags to enable/disable legacy/modern
  2015-03-02 12:34   ` Michael S. Tsirkin
@ 2015-03-02 13:25     ` Gerd Hoffmann
  0 siblings, 0 replies; 44+ messages in thread
From: Gerd Hoffmann @ 2015-03-02 13:25 UTC (permalink / raw)
  To: Michael S. Tsirkin; +Cc: qemu-devel, Anthony Liguori

  Hi,

> I merged patches 1 and 2. I'm guessing you don't want gpu merged yet?

Thanks.  Yes, gpu not yet, and I plan to merge that through my vga queue
anyway (once all virtio dependencies are upstream).

cheers,
  Gerd

^ permalink raw reply	[flat|nested] 44+ messages in thread

end of thread, other threads:[~2015-03-02 13:26 UTC | newest]

Thread overview: 44+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-02-23 10:23 [Qemu-devel] [RfC PATCH 00/15] virtio-gpu: Gerd Hoffmann
2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 01/15] virtio-pci: add flags to enable/disable legacy/modern Gerd Hoffmann
2015-02-26 16:41   ` Max Reitz
2015-02-27 11:15     ` Gerd Hoffmann
2015-02-27 14:20       ` Max Reitz
2015-03-02 12:34   ` Michael S. Tsirkin
2015-03-02 13:25     ` Gerd Hoffmann
2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 02/15] virtio-pci: make QEMU_VIRTIO_PCI_QUEUE_MEM_MULT smaller Gerd Hoffmann
2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 03/15] virtio-pci: make pci bars configurable Gerd Hoffmann
2015-03-02 12:30   ` Michael S. Tsirkin
2015-03-02 13:10     ` Gerd Hoffmann
2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 04/15] virtio-pci: make modern bar 64bit prefetchable Gerd Hoffmann
2015-03-02 12:33   ` Michael S. Tsirkin
2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 05/15] virtio-gpu/2d: add hardware spec include file Gerd Hoffmann
2015-02-25 20:04   ` Max Reitz
2015-02-27  9:37     ` Gerd Hoffmann
2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 06/15] virtio-gpu/2d: add virtio gpu core code Gerd Hoffmann
2015-02-26 16:08   ` Max Reitz
2015-02-27 11:10     ` Gerd Hoffmann
2015-02-27 14:20       ` Max Reitz
2015-02-27 14:31         ` Gerd Hoffmann
2015-02-27 14:33           ` Max Reitz
2015-03-01 22:03     ` Dave Airlie
2015-03-02 12:57       ` Gerd Hoffmann
2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 07/15] virtio-gpu-pci: add virtio pci support Gerd Hoffmann
2015-02-26 16:25   ` Max Reitz
2015-02-27 11:13     ` Gerd Hoffmann
2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 08/15] virtio-gpu-pci: virtio-1.0 adaptions [fixup] Gerd Hoffmann
2015-02-26 16:46   ` Max Reitz
2015-02-27 11:18     ` Gerd Hoffmann
2015-02-27 14:30       ` Max Reitz
2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 09/15] virtio-vga: add virtio gpu device with vga compatibility Gerd Hoffmann
2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 10/15] virtio-vga: virtio-1.0 adaptions [fixup] Gerd Hoffmann
2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 11/15] virtio-vga: add '-vga virtio' support Gerd Hoffmann
2015-02-24 16:26   ` Marc-André Lureau
2015-02-27  9:27     ` Gerd Hoffmann
2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 12/15] virtio-vga: add vgabios configuration Gerd Hoffmann
2015-02-26 18:13   ` Max Reitz
2015-02-27 11:25     ` Gerd Hoffmann
2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 13/15] virtio-vga: add vgabios binary Gerd Hoffmann
2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 14/15] virtio-gpu: add to display-vga test Gerd Hoffmann
2015-02-23 10:23 ` [Qemu-devel] [RfC PATCH 15/15] [hack] virtio-gpu: maskerade as -device VGA Gerd Hoffmann
2015-02-26 18:40 ` [Qemu-devel] [RfC PATCH 00/15] virtio-gpu: Max Reitz
2015-02-27 11:30   ` Gerd Hoffmann

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.