summary refs log tree commit diff stats
path: root/hw/display
diff options
context:
space:
mode:
Diffstat (limited to 'hw/display')
-rw-r--r--hw/display/Makefile.objs2
-rw-r--r--hw/display/vga-pci.c8
-rw-r--r--hw/display/vga_int.h6
-rw-r--r--hw/display/virtio-gpu-pci.c68
-rw-r--r--hw/display/virtio-gpu.c2
-rw-r--r--hw/display/virtio-vga.c175
6 files changed, 256 insertions, 5 deletions
diff --git a/hw/display/Makefile.objs b/hw/display/Makefile.objs
index 61c80f319d..dd8ea76d17 100644
--- a/hw/display/Makefile.objs
+++ b/hw/display/Makefile.objs
@@ -36,3 +36,5 @@ 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
+obj-$(CONFIG_VIRTIO_VGA) += virtio-vga.o
diff --git a/hw/display/vga-pci.c b/hw/display/vga-pci.c
index 0ed44c7831..1dfa331e60 100644
--- a/hw/display/vga-pci.c
+++ b/hw/display/vga-pci.c
@@ -204,10 +204,10 @@ static const MemoryRegionOps pci_vga_qext_ops = {
     .endianness = DEVICE_LITTLE_ENDIAN,
 };
 
-static void pci_std_vga_mmio_region_init(VGACommonState *s,
-                                         MemoryRegion *parent,
-                                         MemoryRegion *subs,
-                                         bool qext)
+void pci_std_vga_mmio_region_init(VGACommonState *s,
+                                  MemoryRegion *parent,
+                                  MemoryRegion *subs,
+                                  bool qext)
 {
     memory_region_init_io(&subs[0], NULL, &pci_vga_ioport_ops, s,
                           "vga ioports remapped", PCI_VGA_IOPORT_SIZE);
diff --git a/hw/display/vga_int.h b/hw/display/vga_int.h
index fcfcc5f431..40ba6a4207 100644
--- a/hw/display/vga_int.h
+++ b/hw/display/vga_int.h
@@ -219,4 +219,10 @@ extern const uint8_t gr_mask[16];
 
 extern const MemoryRegionOps vga_mem_ops;
 
+/* vga-pci.c */
+void pci_std_vga_mmio_region_init(VGACommonState *s,
+                                  MemoryRegion *parent,
+                                  MemoryRegion *subs,
+                                  bool qext);
+
 #endif
diff --git a/hw/display/virtio-gpu-pci.c b/hw/display/virtio-gpu-pci.c
new file mode 100644
index 0000000000..f0f25c7bc9
--- /dev/null
+++ b/hw/display/virtio-gpu-pci.c
@@ -0,0 +1,68 @@
+/*
+ * 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 void virtio_gpu_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
+{
+    VirtIOGPUPCI *vgpu = VIRTIO_GPU_PCI(vpci_dev);
+    DeviceState *vdev = DEVICE(&vgpu->vdev);
+
+    qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
+    /* force virtio-1.0 */
+    vpci_dev->flags &= ~VIRTIO_PCI_FLAG_DISABLE_MODERN;
+    vpci_dev->flags |= VIRTIO_PCI_FLAG_DISABLE_LEGACY;
+    object_property_set_bool(OBJECT(vdev), true, "realized", errp);
+}
+
+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->realize = virtio_gpu_pci_realize;
+    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/display/virtio-gpu.c b/hw/display/virtio-gpu.c
index 4b10ca1ebb..8c109b79f4 100644
--- a/hw/display/virtio-gpu.c
+++ b/hw/display/virtio-gpu.c
@@ -534,7 +534,7 @@ int virtio_gpu_create_mapping_iov(struct virtio_gpu_resource_attach_backing *ab,
 
     if (ab->nr_entries > 16384) {
         qemu_log_mask(LOG_GUEST_ERROR,
-                      "%s: nr_entries is too big (%d > 1024)\n",
+                      "%s: nr_entries is too big (%d > 16384)\n",
                       __func__, ab->nr_entries);
         return -1;
     }
diff --git a/hw/display/virtio-vga.c b/hw/display/virtio-vga.c
new file mode 100644
index 0000000000..94f9d0eb5a
--- /dev/null
+++ b/hw/display/virtio-vga.c
@@ -0,0 +1,175 @@
+#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;
+    MemoryRegion   vga_mrs[3];
+} 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 void virtio_vga_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
+{
+    VirtIOVGA *vvga = VIRTIO_VGA(vpci_dev);
+    VirtIOGPU *g = &vvga->vdev;
+    VGACommonState *vga = &vvga->vga;
+    uint32_t offset;
+
+    /* init vga compat bits */
+    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);
+    pci_register_bar(&vpci_dev->pci_dev, 0,
+                     PCI_BASE_ADDRESS_MEM_PREFETCH, &vga->vram);
+
+    /*
+     * Configure virtio bar and regions
+     *
+     * We use bar #2 for the mmio regions, to be compatible with stdvga.
+     * virtio regions are moved to the end of bar #2, to make room for
+     * the stdvga mmio registers at the start of bar #2.
+     */
+    vpci_dev->modern_mem_bar = 2;
+    vpci_dev->msix_bar = 4;
+    offset = memory_region_size(&vpci_dev->modern_bar);
+    offset -= vpci_dev->notify.size;
+    vpci_dev->notify.offset = offset;
+    offset -= vpci_dev->device.size;
+    vpci_dev->device.offset = offset;
+    offset -= vpci_dev->isr.size;
+    vpci_dev->isr.offset = offset;
+    offset -= vpci_dev->common.size;
+    vpci_dev->common.offset = offset;
+
+    /* init virtio bits */
+    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;
+    object_property_set_bool(OBJECT(g), true, "realized", errp);
+
+    /* add stdvga mmio regions */
+    pci_std_vga_mmio_region_init(vga, &vpci_dev->modern_bar,
+                                 vvga->vga_mrs, true);
+
+    vga->con = g->scanout[0].con;
+    graphic_console_set_hwops(vga->con, &virtio_vga_ops, vvga);
+}
+
+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->realize = virtio_vga_realize;
+    pcidev_k->romfile = "vgabios-virtio.bin";
+    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)