From: Dave Airlie <airl...@redhat.com> This is a virtio-vga device built on top of the virtio-gpu device.
Signed-off-by: Dave Airlie <airl...@redhat.com> --- Makefile | 2 +- default-configs/x86_64-softmmu.mak | 1 + hw/display/Makefile.objs | 1 + hw/display/virtio-vga.c | 156 +++++++++++++++++++++++++++++++++++++ hw/pci/pci.c | 2 + include/sysemu/sysemu.h | 2 +- pc-bios/vgabios-virtio.bin | Bin 0 -> 40448 bytes roms/Makefile | 2 +- roms/config.vga.virtio | 6 ++ vl.c | 13 ++++ 10 files changed, 182 insertions(+), 3 deletions(-) create mode 100644 hw/display/virtio-vga.c create mode 100644 pc-bios/vgabios-virtio.bin create mode 100644 roms/config.vga.virtio diff --git a/Makefile b/Makefile index bdff4e4..a7dabe4 100644 --- a/Makefile +++ b/Makefile @@ -291,7 +291,7 @@ bepo cz ifdef INSTALL_BLOBS BLOBS=bios.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 \ pxe-e1000.rom pxe-eepro100.rom pxe-ne2k_pci.rom \ diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak index 1a00b78..22d8587 100644 --- a/default-configs/x86_64-softmmu.mak +++ b/default-configs/x86_64-softmmu.mak @@ -10,6 +10,7 @@ CONFIG_VGA_ISA=y CONFIG_VGA_CIRRUS=y CONFIG_VMWARE_VGA=y CONFIG_VIRTIO_GPU=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 10e4066..63427e9 100644 --- a/hw/display/Makefile.objs +++ b/hw/display/Makefile.objs @@ -34,3 +34,4 @@ obj-$(CONFIG_VGA) += vga.o common-obj-$(CONFIG_QXL) += qxl.o qxl-logger.o qxl-render.o obj-$(CONFIG_VIRTIO_GPU) += virtio-gpu.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..9e8eff9 --- /dev/null +++ b/hw/display/virtio-vga.c @@ -0,0 +1,156 @@ +#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 VirtIOGPUPCI + */ +#define TYPE_VIRTIO_VGA "virtio-vga" +#define VIRTIO_VGA(obj) \ + OBJECT_CHECK(VirtIOVGA, (obj), TYPE_VIRTIO_VGA) + +typedef struct VirtIOVGA VirtIOVGA; +struct VirtIOVGA { + struct VirtIOGPUPCI gpu; + VGACommonState vga; + const struct GraphicHwOps *wrapped_ops; + void *wrapped_opaque; +}; + +static void virtio_vga_invalidate_display(void *opaque) +{ + VirtIOVGA *vvga = opaque; + + if (!vvga->gpu.vdev.enable) { + vvga->vga.hw_ops->invalidate(&vvga->vga); + return; + } + + vvga->wrapped_ops->invalidate(vvga->wrapped_opaque); +} + +static void virtio_vga_update_display(void *opaque) +{ + VirtIOVGA *vvga = opaque; + + if (!vvga->gpu.vdev.enable) { + vvga->vga.hw_ops->gfx_update(&vvga->vga); + } + vvga->wrapped_ops->gfx_update(vvga->wrapped_opaque); +} + +static void virtio_vga_text_update(void *opaque, console_ch_t *chardata) +{ + VirtIOVGA *vvga = opaque; + + if (!vvga->gpu.vdev.enable) { + if (vvga->vga.hw_ops->text_update) + vvga->vga.hw_ops->text_update(&vvga->vga, chardata); + } + vvga->wrapped_ops->text_update(vvga->wrapped_opaque, chardata); +} + +static void virtio_vga_notify_state(void *opaque, int idx, int x, int y, uint32_t width, uint32_t height) +{ + VirtIOVGA *vvga = opaque; + + if (!vvga->gpu.vdev.enable) { + if (vvga->vga.hw_ops->notify_state) + vvga->vga.hw_ops->notify_state(&vvga->vga, idx, x, y, width, height); + } + vvga->wrapped_ops->notify_state(vvga->wrapped_opaque, idx, x, y, width, height); +} + +static const GraphicHwOps virtio_vga_ops = { + .invalidate = virtio_vga_invalidate_display, + .gfx_update = virtio_vga_update_display, + .text_update = virtio_vga_text_update, + .notify_state = virtio_vga_notify_state, +}; + +/* VGA device wrapper around PCI device around virtio GPU */ +static int virtio_vga_init(VirtIOPCIProxy *vpci_dev) +{ + VirtIOVGA *vvga = VIRTIO_VGA(vpci_dev); + DeviceState *vdev = DEVICE(&vvga->gpu.vdev); + VGACommonState *vga = &vvga->vga; + + qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); + if (qdev_init(vdev) < 0) { + return -1; + } + + graphic_console_wrap(vvga->gpu.vdev.con[0], DEVICE(vpci_dev), &virtio_vga_ops, vvga, &vvga->wrapped_ops, &vvga->wrapped_opaque); + vga->con = vvga->gpu.vdev.con[0]; + + vga_common_init(vga, OBJECT(vpci_dev)); + 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, 2, PCI_BASE_ADDRESS_MEM_PREFETCH, &vga->vram); + + if (!vpci_dev->pci_dev.rom_bar) { + /* compatibility with pc-0.13 and older */ + vga_init_vbe(vga, OBJECT(vpci_dev), pci_address_space(&vpci_dev->pci_dev)); + } + + return 0; +} + +static void virtio_vga_reset(DeviceState *dev) +{ + VirtIOVGA *vvga = VIRTIO_VGA(dev); + vvga->gpu.vdev.enable = 0; + + vga_dirty_log_start(&vvga->vga); +} + +static Property virtio_vga_properties[] = { + DEFINE_VIRTIO_GPU_PROPERTIES(VirtIOVGA, gpu.vdev.conf), + DEFINE_VIRTIO_GPU_PCI_PROPERTIES(VirtIOPCIProxy), + DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features), + DEFINE_PROP_UINT32("vgamem_mb", VirtIOVGA, vga.vram_size_mb, 16), + 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; + + k->init = virtio_vga_init; + pcidev_k->no_hotplug = 1; + 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->gpu.vdev, sizeof(dev->gpu.vdev), TYPE_VIRTIO_GPU); + object_property_add_child(obj, "virtio-backend", OBJECT(&dev->gpu.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 virgl_register_types(void) +{ + type_register_static(&virtio_vga_info); +} + +type_init(virgl_register_types) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 49eca95..9d92d92 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -1655,6 +1655,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 495dae8..1d6ec39 100644 --- a/include/sysemu/sysemu.h +++ b/include/sysemu/sysemu.h @@ -103,7 +103,7 @@ typedef enum DisplayType extern int autostart; typedef enum { - VGA_NONE, VGA_STD, VGA_CIRRUS, VGA_VMWARE, VGA_XENFB, VGA_QXL, + VGA_NONE, VGA_STD, VGA_CIRRUS, VGA_VMWARE, VGA_XENFB, VGA_QXL, VGA_VIRTIO } VGAInterfaceType; extern int vga_interface_type; diff --git a/pc-bios/vgabios-virtio.bin b/pc-bios/vgabios-virtio.bin new file mode 100644 index 0000000000000000000000000000000000000000..2b70d272f2704e7839712a61613844321b93b465 GIT binary patch literal 40448 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 AD*ylh literal 0 HcmV?d00001 diff --git a/roms/Makefile b/roms/Makefile index 1e04669..9e51a79 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 diff --git a/vl.c b/vl.c index b0399de..1915ed6 100644 --- a/vl.c +++ b/vl.c @@ -299,6 +299,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 = { @@ -2082,6 +2083,11 @@ static bool qxl_vga_available(void) return object_class_by_name("qxl-vga"); } +static bool virtio_vga_available(void) +{ + return object_class_by_name("virtio-vga"); +} + static void select_vgahw (const char *p) { const char *opts; @@ -2108,6 +2114,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