aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-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
-rw-r--r--hw/isa/isa-bus.c3
-rw-r--r--hw/pci/pci.c2
-rw-r--r--hw/virtio/virtio-pci.h14
9 files changed, 275 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)
diff --git a/hw/isa/isa-bus.c b/hw/isa/isa-bus.c
index ec8e7decfc..43e0cd8ddd 100644
--- a/hw/isa/isa-bus.c
+++ b/hw/isa/isa-bus.c
@@ -179,6 +179,9 @@ ISADevice *isa_vga_init(ISABus *bus)
case VGA_VMWARE:
fprintf(stderr, "%s: vmware_vga: no PCI bus\n", __func__);
return NULL;
+ case VGA_VIRTIO:
+ fprintf(stderr, "%s: virtio-vga: no PCI bus\n", __func__);
+ return NULL;
case VGA_NONE:
default:
return NULL;
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index 750f3dacea..21580433d4 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -1698,6 +1698,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/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h
index d962125351..96025ca205 100644
--- a/hw/virtio/virtio-pci.h
+++ b/hw/virtio/virtio-pci.h
@@ -25,6 +25,7 @@
#include "hw/virtio/virtio-bus.h"
#include "hw/virtio/virtio-9p.h"
#include "hw/virtio/virtio-input.h"
+#include "hw/virtio/virtio-gpu.h"
#ifdef CONFIG_VIRTFS
#include "hw/9pfs/virtio-9p.h"
#endif
@@ -42,6 +43,7 @@ typedef struct VHostSCSIPCI VHostSCSIPCI;
typedef struct VirtIORngPCI VirtIORngPCI;
typedef struct VirtIOInputPCI VirtIOInputPCI;
typedef struct VirtIOInputHIDPCI VirtIOInputHIDPCI;
+typedef struct VirtIOGPUPCI VirtIOGPUPCI;
/* virtio-pci-bus */
@@ -261,6 +263,18 @@ struct VirtIOInputHIDPCI {
VirtIOInputHID 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