-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
virtio-vga: add virtio gpu device with vga compatibility
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. It is compatible with stdvga. Written by Dave Airlie and Gerd Hoffmann. Signed-off-by: Dave Airlie <[email protected]> Signed-off-by: Gerd Hoffmann <[email protected]>
- Loading branch information
Showing
5 changed files
with
187 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) |