1*c5d4dac8SGerd Hoffmann #include "hw/hw.h" 2*c5d4dac8SGerd Hoffmann #include "hw/pci/pci.h" 3*c5d4dac8SGerd Hoffmann #include "ui/console.h" 4*c5d4dac8SGerd Hoffmann #include "vga_int.h" 5*c5d4dac8SGerd Hoffmann #include "hw/virtio/virtio-pci.h" 6*c5d4dac8SGerd Hoffmann 7*c5d4dac8SGerd Hoffmann /* 8*c5d4dac8SGerd Hoffmann * virtio-vga: This extends VirtioPCIProxy. 9*c5d4dac8SGerd Hoffmann */ 10*c5d4dac8SGerd Hoffmann #define TYPE_VIRTIO_VGA "virtio-vga" 11*c5d4dac8SGerd Hoffmann #define VIRTIO_VGA(obj) \ 12*c5d4dac8SGerd Hoffmann OBJECT_CHECK(VirtIOVGA, (obj), TYPE_VIRTIO_VGA) 13*c5d4dac8SGerd Hoffmann 14*c5d4dac8SGerd Hoffmann typedef struct VirtIOVGA { 15*c5d4dac8SGerd Hoffmann VirtIOPCIProxy parent_obj; 16*c5d4dac8SGerd Hoffmann VirtIOGPU vdev; 17*c5d4dac8SGerd Hoffmann VGACommonState vga; 18*c5d4dac8SGerd Hoffmann MemoryRegion vga_mrs[3]; 19*c5d4dac8SGerd Hoffmann } VirtIOVGA; 20*c5d4dac8SGerd Hoffmann 21*c5d4dac8SGerd Hoffmann static void virtio_vga_invalidate_display(void *opaque) 22*c5d4dac8SGerd Hoffmann { 23*c5d4dac8SGerd Hoffmann VirtIOVGA *vvga = opaque; 24*c5d4dac8SGerd Hoffmann 25*c5d4dac8SGerd Hoffmann if (vvga->vdev.enable) { 26*c5d4dac8SGerd Hoffmann virtio_gpu_ops.invalidate(&vvga->vdev); 27*c5d4dac8SGerd Hoffmann } else { 28*c5d4dac8SGerd Hoffmann vvga->vga.hw_ops->invalidate(&vvga->vga); 29*c5d4dac8SGerd Hoffmann } 30*c5d4dac8SGerd Hoffmann } 31*c5d4dac8SGerd Hoffmann 32*c5d4dac8SGerd Hoffmann static void virtio_vga_update_display(void *opaque) 33*c5d4dac8SGerd Hoffmann { 34*c5d4dac8SGerd Hoffmann VirtIOVGA *vvga = opaque; 35*c5d4dac8SGerd Hoffmann 36*c5d4dac8SGerd Hoffmann if (vvga->vdev.enable) { 37*c5d4dac8SGerd Hoffmann virtio_gpu_ops.gfx_update(&vvga->vdev); 38*c5d4dac8SGerd Hoffmann } else { 39*c5d4dac8SGerd Hoffmann vvga->vga.hw_ops->gfx_update(&vvga->vga); 40*c5d4dac8SGerd Hoffmann } 41*c5d4dac8SGerd Hoffmann } 42*c5d4dac8SGerd Hoffmann 43*c5d4dac8SGerd Hoffmann static void virtio_vga_text_update(void *opaque, console_ch_t *chardata) 44*c5d4dac8SGerd Hoffmann { 45*c5d4dac8SGerd Hoffmann VirtIOVGA *vvga = opaque; 46*c5d4dac8SGerd Hoffmann 47*c5d4dac8SGerd Hoffmann if (vvga->vdev.enable) { 48*c5d4dac8SGerd Hoffmann if (virtio_gpu_ops.text_update) { 49*c5d4dac8SGerd Hoffmann virtio_gpu_ops.text_update(&vvga->vdev, chardata); 50*c5d4dac8SGerd Hoffmann } 51*c5d4dac8SGerd Hoffmann } else { 52*c5d4dac8SGerd Hoffmann if (vvga->vga.hw_ops->text_update) { 53*c5d4dac8SGerd Hoffmann vvga->vga.hw_ops->text_update(&vvga->vga, chardata); 54*c5d4dac8SGerd Hoffmann } 55*c5d4dac8SGerd Hoffmann } 56*c5d4dac8SGerd Hoffmann } 57*c5d4dac8SGerd Hoffmann 58*c5d4dac8SGerd Hoffmann static int virtio_vga_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info) 59*c5d4dac8SGerd Hoffmann { 60*c5d4dac8SGerd Hoffmann VirtIOVGA *vvga = opaque; 61*c5d4dac8SGerd Hoffmann 62*c5d4dac8SGerd Hoffmann if (virtio_gpu_ops.ui_info) { 63*c5d4dac8SGerd Hoffmann return virtio_gpu_ops.ui_info(&vvga->vdev, idx, info); 64*c5d4dac8SGerd Hoffmann } 65*c5d4dac8SGerd Hoffmann return -1; 66*c5d4dac8SGerd Hoffmann } 67*c5d4dac8SGerd Hoffmann 68*c5d4dac8SGerd Hoffmann static const GraphicHwOps virtio_vga_ops = { 69*c5d4dac8SGerd Hoffmann .invalidate = virtio_vga_invalidate_display, 70*c5d4dac8SGerd Hoffmann .gfx_update = virtio_vga_update_display, 71*c5d4dac8SGerd Hoffmann .text_update = virtio_vga_text_update, 72*c5d4dac8SGerd Hoffmann .ui_info = virtio_vga_ui_info, 73*c5d4dac8SGerd Hoffmann }; 74*c5d4dac8SGerd Hoffmann 75*c5d4dac8SGerd Hoffmann /* VGA device wrapper around PCI device around virtio GPU */ 76*c5d4dac8SGerd Hoffmann static void virtio_vga_realize(VirtIOPCIProxy *vpci_dev, Error **errp) 77*c5d4dac8SGerd Hoffmann { 78*c5d4dac8SGerd Hoffmann VirtIOVGA *vvga = VIRTIO_VGA(vpci_dev); 79*c5d4dac8SGerd Hoffmann VirtIOGPU *g = &vvga->vdev; 80*c5d4dac8SGerd Hoffmann VGACommonState *vga = &vvga->vga; 81*c5d4dac8SGerd Hoffmann uint32_t offset; 82*c5d4dac8SGerd Hoffmann 83*c5d4dac8SGerd Hoffmann /* init vga compat bits */ 84*c5d4dac8SGerd Hoffmann vga->vram_size_mb = 8; 85*c5d4dac8SGerd Hoffmann vga_common_init(vga, OBJECT(vpci_dev), false); 86*c5d4dac8SGerd Hoffmann vga_init(vga, OBJECT(vpci_dev), pci_address_space(&vpci_dev->pci_dev), 87*c5d4dac8SGerd Hoffmann pci_address_space_io(&vpci_dev->pci_dev), true); 88*c5d4dac8SGerd Hoffmann pci_register_bar(&vpci_dev->pci_dev, 0, 89*c5d4dac8SGerd Hoffmann PCI_BASE_ADDRESS_MEM_PREFETCH, &vga->vram); 90*c5d4dac8SGerd Hoffmann 91*c5d4dac8SGerd Hoffmann /* 92*c5d4dac8SGerd Hoffmann * Configure virtio bar and regions 93*c5d4dac8SGerd Hoffmann * 94*c5d4dac8SGerd Hoffmann * We use bar #2 for the mmio regions, to be compatible with stdvga. 95*c5d4dac8SGerd Hoffmann * virtio regions are moved to the end of bar #2, to make room for 96*c5d4dac8SGerd Hoffmann * the stdvga mmio registers at the start of bar #2. 97*c5d4dac8SGerd Hoffmann */ 98*c5d4dac8SGerd Hoffmann vpci_dev->modern_mem_bar = 2; 99*c5d4dac8SGerd Hoffmann vpci_dev->msix_bar = 4; 100*c5d4dac8SGerd Hoffmann offset = memory_region_size(&vpci_dev->modern_bar); 101*c5d4dac8SGerd Hoffmann offset -= vpci_dev->notify.size; 102*c5d4dac8SGerd Hoffmann vpci_dev->notify.offset = offset; 103*c5d4dac8SGerd Hoffmann offset -= vpci_dev->device.size; 104*c5d4dac8SGerd Hoffmann vpci_dev->device.offset = offset; 105*c5d4dac8SGerd Hoffmann offset -= vpci_dev->isr.size; 106*c5d4dac8SGerd Hoffmann vpci_dev->isr.offset = offset; 107*c5d4dac8SGerd Hoffmann offset -= vpci_dev->common.size; 108*c5d4dac8SGerd Hoffmann vpci_dev->common.offset = offset; 109*c5d4dac8SGerd Hoffmann 110*c5d4dac8SGerd Hoffmann /* init virtio bits */ 111*c5d4dac8SGerd Hoffmann qdev_set_parent_bus(DEVICE(g), BUS(&vpci_dev->bus)); 112*c5d4dac8SGerd Hoffmann /* force virtio-1.0 */ 113*c5d4dac8SGerd Hoffmann vpci_dev->flags &= ~VIRTIO_PCI_FLAG_DISABLE_MODERN; 114*c5d4dac8SGerd Hoffmann vpci_dev->flags |= VIRTIO_PCI_FLAG_DISABLE_LEGACY; 115*c5d4dac8SGerd Hoffmann object_property_set_bool(OBJECT(g), true, "realized", errp); 116*c5d4dac8SGerd Hoffmann 117*c5d4dac8SGerd Hoffmann /* add stdvga mmio regions */ 118*c5d4dac8SGerd Hoffmann pci_std_vga_mmio_region_init(vga, &vpci_dev->modern_bar, 119*c5d4dac8SGerd Hoffmann vvga->vga_mrs, true); 120*c5d4dac8SGerd Hoffmann 121*c5d4dac8SGerd Hoffmann vga->con = g->scanout[0].con; 122*c5d4dac8SGerd Hoffmann graphic_console_set_hwops(vga->con, &virtio_vga_ops, vvga); 123*c5d4dac8SGerd Hoffmann } 124*c5d4dac8SGerd Hoffmann 125*c5d4dac8SGerd Hoffmann static void virtio_vga_reset(DeviceState *dev) 126*c5d4dac8SGerd Hoffmann { 127*c5d4dac8SGerd Hoffmann VirtIOVGA *vvga = VIRTIO_VGA(dev); 128*c5d4dac8SGerd Hoffmann vvga->vdev.enable = 0; 129*c5d4dac8SGerd Hoffmann 130*c5d4dac8SGerd Hoffmann vga_dirty_log_start(&vvga->vga); 131*c5d4dac8SGerd Hoffmann } 132*c5d4dac8SGerd Hoffmann 133*c5d4dac8SGerd Hoffmann static Property virtio_vga_properties[] = { 134*c5d4dac8SGerd Hoffmann DEFINE_VIRTIO_GPU_PROPERTIES(VirtIOVGA, vdev.conf), 135*c5d4dac8SGerd Hoffmann DEFINE_VIRTIO_GPU_PCI_PROPERTIES(VirtIOPCIProxy), 136*c5d4dac8SGerd Hoffmann DEFINE_PROP_END_OF_LIST(), 137*c5d4dac8SGerd Hoffmann }; 138*c5d4dac8SGerd Hoffmann 139*c5d4dac8SGerd Hoffmann static void virtio_vga_class_init(ObjectClass *klass, void *data) 140*c5d4dac8SGerd Hoffmann { 141*c5d4dac8SGerd Hoffmann DeviceClass *dc = DEVICE_CLASS(klass); 142*c5d4dac8SGerd Hoffmann VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); 143*c5d4dac8SGerd Hoffmann PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); 144*c5d4dac8SGerd Hoffmann 145*c5d4dac8SGerd Hoffmann set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); 146*c5d4dac8SGerd Hoffmann dc->props = virtio_vga_properties; 147*c5d4dac8SGerd Hoffmann dc->reset = virtio_vga_reset; 148*c5d4dac8SGerd Hoffmann dc->hotpluggable = false; 149*c5d4dac8SGerd Hoffmann 150*c5d4dac8SGerd Hoffmann k->realize = virtio_vga_realize; 151*c5d4dac8SGerd Hoffmann pcidev_k->romfile = "vgabios-virtio.bin"; 152*c5d4dac8SGerd Hoffmann pcidev_k->class_id = PCI_CLASS_DISPLAY_VGA; 153*c5d4dac8SGerd Hoffmann } 154*c5d4dac8SGerd Hoffmann 155*c5d4dac8SGerd Hoffmann static void virtio_vga_inst_initfn(Object *obj) 156*c5d4dac8SGerd Hoffmann { 157*c5d4dac8SGerd Hoffmann VirtIOVGA *dev = VIRTIO_VGA(obj); 158*c5d4dac8SGerd Hoffmann object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_GPU); 159*c5d4dac8SGerd Hoffmann object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL); 160*c5d4dac8SGerd Hoffmann } 161*c5d4dac8SGerd Hoffmann 162*c5d4dac8SGerd Hoffmann static TypeInfo virtio_vga_info = { 163*c5d4dac8SGerd Hoffmann .name = TYPE_VIRTIO_VGA, 164*c5d4dac8SGerd Hoffmann .parent = TYPE_VIRTIO_PCI, 165*c5d4dac8SGerd Hoffmann .instance_size = sizeof(struct VirtIOVGA), 166*c5d4dac8SGerd Hoffmann .instance_init = virtio_vga_inst_initfn, 167*c5d4dac8SGerd Hoffmann .class_init = virtio_vga_class_init, 168*c5d4dac8SGerd Hoffmann }; 169*c5d4dac8SGerd Hoffmann 170*c5d4dac8SGerd Hoffmann static void virtio_vga_register_types(void) 171*c5d4dac8SGerd Hoffmann { 172*c5d4dac8SGerd Hoffmann type_register_static(&virtio_vga_info); 173*c5d4dac8SGerd Hoffmann } 174*c5d4dac8SGerd Hoffmann 175*c5d4dac8SGerd Hoffmann type_init(virtio_vga_register_types) 176