]>
Commit | Line | Data |
---|---|---|
9b8bfe21 | 1 | #include "qemu/osdep.h" |
c5d4dac8 | 2 | #include "hw/pci/pci.h" |
a27bd6c7 | 3 | #include "hw/qdev-properties.h" |
7ecb381f | 4 | #include "hw/virtio/virtio-gpu.h" |
d0f0c865 | 5 | #include "qapi/error.h" |
0b8fa32f | 6 | #include "qemu/module.h" |
c68082c4 | 7 | #include "virtio-vga.h" |
db1015e9 | 8 | #include "qom/object.h" |
c5d4dac8 | 9 | |
c68082c4 | 10 | static void virtio_vga_base_invalidate_display(void *opaque) |
c5d4dac8 | 11 | { |
c68082c4 MAL |
12 | VirtIOVGABase *vvga = opaque; |
13 | VirtIOGPUBase *g = vvga->vgpu; | |
c5d4dac8 | 14 | |
50d8e25e | 15 | if (g->enable) { |
3b593b3f | 16 | g->hw_ops->invalidate(g); |
c5d4dac8 GH |
17 | } else { |
18 | vvga->vga.hw_ops->invalidate(&vvga->vga); | |
19 | } | |
20 | } | |
21 | ||
c68082c4 | 22 | static void virtio_vga_base_update_display(void *opaque) |
c5d4dac8 | 23 | { |
c68082c4 MAL |
24 | VirtIOVGABase *vvga = opaque; |
25 | VirtIOGPUBase *g = vvga->vgpu; | |
c5d4dac8 | 26 | |
50d8e25e | 27 | if (g->enable) { |
3b593b3f | 28 | g->hw_ops->gfx_update(g); |
c5d4dac8 GH |
29 | } else { |
30 | vvga->vga.hw_ops->gfx_update(&vvga->vga); | |
31 | } | |
32 | } | |
33 | ||
c68082c4 | 34 | static void virtio_vga_base_text_update(void *opaque, console_ch_t *chardata) |
c5d4dac8 | 35 | { |
c68082c4 MAL |
36 | VirtIOVGABase *vvga = opaque; |
37 | VirtIOGPUBase *g = vvga->vgpu; | |
c5d4dac8 | 38 | |
50d8e25e | 39 | if (g->enable) { |
3b593b3f GH |
40 | if (g->hw_ops->text_update) { |
41 | g->hw_ops->text_update(g, chardata); | |
c5d4dac8 GH |
42 | } |
43 | } else { | |
44 | if (vvga->vga.hw_ops->text_update) { | |
45 | vvga->vga.hw_ops->text_update(&vvga->vga, chardata); | |
46 | } | |
47 | } | |
48 | } | |
49 | ||
362239c0 | 50 | static void virtio_vga_base_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info) |
c5d4dac8 | 51 | { |
c68082c4 MAL |
52 | VirtIOVGABase *vvga = opaque; |
53 | VirtIOGPUBase *g = vvga->vgpu; | |
c5d4dac8 | 54 | |
3b593b3f | 55 | if (g->hw_ops->ui_info) { |
362239c0 | 56 | g->hw_ops->ui_info(g, idx, info); |
c5d4dac8 | 57 | } |
c5d4dac8 GH |
58 | } |
59 | ||
c68082c4 | 60 | static void virtio_vga_base_gl_block(void *opaque, bool block) |
321c9adb | 61 | { |
c68082c4 MAL |
62 | VirtIOVGABase *vvga = opaque; |
63 | VirtIOGPUBase *g = vvga->vgpu; | |
321c9adb | 64 | |
3b593b3f GH |
65 | if (g->hw_ops->gl_block) { |
66 | g->hw_ops->gl_block(g, block); | |
321c9adb GH |
67 | } |
68 | } | |
69 | ||
a7dfbe28 MAL |
70 | static int virtio_vga_base_get_flags(void *opaque) |
71 | { | |
72 | VirtIOVGABase *vvga = opaque; | |
73 | VirtIOGPUBase *g = vvga->vgpu; | |
74 | ||
75 | return g->hw_ops->get_flags(g); | |
76 | } | |
77 | ||
c68082c4 | 78 | static const GraphicHwOps virtio_vga_base_ops = { |
a7dfbe28 | 79 | .get_flags = virtio_vga_base_get_flags, |
c68082c4 MAL |
80 | .invalidate = virtio_vga_base_invalidate_display, |
81 | .gfx_update = virtio_vga_base_update_display, | |
82 | .text_update = virtio_vga_base_text_update, | |
83 | .ui_info = virtio_vga_base_ui_info, | |
84 | .gl_block = virtio_vga_base_gl_block, | |
c5d4dac8 GH |
85 | }; |
86 | ||
c68082c4 | 87 | static const VMStateDescription vmstate_virtio_vga_base = { |
0c244e50 GH |
88 | .name = "virtio-vga", |
89 | .version_id = 2, | |
90 | .minimum_version_id = 2, | |
f0613160 | 91 | .fields = (const VMStateField[]) { |
0c244e50 | 92 | /* no pci stuff here, saving the virtio device will handle that */ |
c68082c4 MAL |
93 | VMSTATE_STRUCT(vga, VirtIOVGABase, 0, |
94 | vmstate_vga_common, VGACommonState), | |
0c244e50 GH |
95 | VMSTATE_END_OF_LIST() |
96 | } | |
97 | }; | |
98 | ||
c5d4dac8 | 99 | /* VGA device wrapper around PCI device around virtio GPU */ |
c68082c4 | 100 | static void virtio_vga_base_realize(VirtIOPCIProxy *vpci_dev, Error **errp) |
c5d4dac8 | 101 | { |
c68082c4 MAL |
102 | VirtIOVGABase *vvga = VIRTIO_VGA_BASE(vpci_dev); |
103 | VirtIOGPUBase *g = vvga->vgpu; | |
c5d4dac8 GH |
104 | VGACommonState *vga = &vvga->vga; |
105 | uint32_t offset; | |
e1888295 | 106 | int i; |
c5d4dac8 GH |
107 | |
108 | /* init vga compat bits */ | |
109 | vga->vram_size_mb = 8; | |
6832deb8 TH |
110 | if (!vga_common_init(vga, OBJECT(vpci_dev), errp)) { |
111 | return; | |
112 | } | |
c5d4dac8 GH |
113 | vga_init(vga, OBJECT(vpci_dev), pci_address_space(&vpci_dev->pci_dev), |
114 | pci_address_space_io(&vpci_dev->pci_dev), true); | |
115 | pci_register_bar(&vpci_dev->pci_dev, 0, | |
116 | PCI_BASE_ADDRESS_MEM_PREFETCH, &vga->vram); | |
117 | ||
15138b5e | 118 | vpci_dev->modern_io_bar_idx = 5; |
c2843e93 | 119 | |
ba62dfa7 GH |
120 | if (!virtio_gpu_hostmem_enabled(g->conf)) { |
121 | /* | |
122 | * Configure virtio bar and regions | |
123 | * | |
124 | * We use bar #2 for the mmio regions, to be compatible with stdvga. | |
125 | * virtio regions are moved to the end of bar #2, to make room for | |
126 | * the stdvga mmio registers at the start of bar #2. | |
127 | */ | |
128 | vpci_dev->modern_mem_bar_idx = 2; | |
129 | vpci_dev->msix_bar_idx = 4; | |
130 | } else { | |
131 | vpci_dev->msix_bar_idx = 1; | |
132 | vpci_dev->modern_mem_bar_idx = 2; | |
133 | memory_region_init(&g->hostmem, OBJECT(g), "virtio-gpu-hostmem", | |
134 | g->conf.hostmem); | |
135 | pci_register_bar(&vpci_dev->pci_dev, 4, | |
136 | PCI_BASE_ADDRESS_SPACE_MEMORY | | |
137 | PCI_BASE_ADDRESS_MEM_PREFETCH | | |
138 | PCI_BASE_ADDRESS_MEM_TYPE_64, | |
139 | &g->hostmem); | |
140 | virtio_pci_add_shm_cap(vpci_dev, 4, 0, g->conf.hostmem, | |
141 | VIRTIO_GPU_SHM_ID_HOST_VISIBLE); | |
142 | } | |
143 | ||
c2843e93 GH |
144 | if (!(vpci_dev->flags & VIRTIO_PCI_FLAG_PAGE_PER_VQ)) { |
145 | /* | |
146 | * with page-per-vq=off there is no padding space we can use | |
147 | * for the stdvga registers. Make the common and isr regions | |
148 | * smaller then. | |
149 | */ | |
150 | vpci_dev->common.size /= 2; | |
151 | vpci_dev->isr.size /= 2; | |
152 | } | |
153 | ||
c5d4dac8 GH |
154 | offset = memory_region_size(&vpci_dev->modern_bar); |
155 | offset -= vpci_dev->notify.size; | |
156 | vpci_dev->notify.offset = offset; | |
157 | offset -= vpci_dev->device.size; | |
158 | vpci_dev->device.offset = offset; | |
159 | offset -= vpci_dev->isr.size; | |
160 | vpci_dev->isr.offset = offset; | |
161 | offset -= vpci_dev->common.size; | |
162 | vpci_dev->common.offset = offset; | |
163 | ||
164 | /* init virtio bits */ | |
dd56040d | 165 | virtio_pci_force_virtio_1(vpci_dev); |
668f62ec | 166 | if (!qdev_realize(DEVICE(g), BUS(&vpci_dev->bus), errp)) { |
d0f0c865 MAL |
167 | return; |
168 | } | |
c5d4dac8 GH |
169 | |
170 | /* add stdvga mmio regions */ | |
93abfc88 | 171 | pci_std_vga_mmio_region_init(vga, OBJECT(vvga), &vpci_dev->modern_bar, |
d46b40fc | 172 | vvga->vga_mrs, true, false); |
c5d4dac8 GH |
173 | |
174 | vga->con = g->scanout[0].con; | |
c68082c4 | 175 | graphic_console_set_hwops(vga->con, &virtio_vga_base_ops, vvga); |
e1888295 GH |
176 | |
177 | for (i = 0; i < g->conf.max_outputs; i++) { | |
5325cc34 MA |
178 | object_property_set_link(OBJECT(g->scanout[i].con), "device", |
179 | OBJECT(vpci_dev), &error_abort); | |
e1888295 | 180 | } |
c5d4dac8 GH |
181 | } |
182 | ||
ad80e367 | 183 | static void virtio_vga_base_reset_hold(Object *obj, ResetType type) |
c5d4dac8 | 184 | { |
0d898904 PM |
185 | VirtIOVGABaseClass *klass = VIRTIO_VGA_BASE_GET_CLASS(obj); |
186 | VirtIOVGABase *vvga = VIRTIO_VGA_BASE(obj); | |
c5d4dac8 | 187 | |
43e4dbe2 | 188 | /* reset virtio-gpu */ |
0d898904 | 189 | if (klass->parent_phases.hold) { |
ad80e367 | 190 | klass->parent_phases.hold(obj, type); |
0d898904 | 191 | } |
43e4dbe2 GH |
192 | |
193 | /* reset vga */ | |
194 | vga_common_reset(&vvga->vga); | |
c5d4dac8 GH |
195 | vga_dirty_log_start(&vvga->vga); |
196 | } | |
197 | ||
8be61ce2 GH |
198 | static bool virtio_vga_get_big_endian_fb(Object *obj, Error **errp) |
199 | { | |
200 | VirtIOVGABase *d = VIRTIO_VGA_BASE(obj); | |
201 | ||
202 | return d->vga.big_endian_fb; | |
203 | } | |
204 | ||
205 | static void virtio_vga_set_big_endian_fb(Object *obj, bool value, Error **errp) | |
206 | { | |
207 | VirtIOVGABase *d = VIRTIO_VGA_BASE(obj); | |
208 | ||
209 | d->vga.big_endian_fb = value; | |
210 | } | |
211 | ||
c68082c4 | 212 | static Property virtio_vga_base_properties[] = { |
c5d4dac8 GH |
213 | DEFINE_VIRTIO_GPU_PCI_PROPERTIES(VirtIOPCIProxy), |
214 | DEFINE_PROP_END_OF_LIST(), | |
215 | }; | |
216 | ||
c68082c4 | 217 | static void virtio_vga_base_class_init(ObjectClass *klass, void *data) |
c5d4dac8 GH |
218 | { |
219 | DeviceClass *dc = DEVICE_CLASS(klass); | |
220 | VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); | |
c68082c4 | 221 | VirtIOVGABaseClass *v = VIRTIO_VGA_BASE_CLASS(klass); |
c5d4dac8 | 222 | PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); |
0d898904 | 223 | ResettableClass *rc = RESETTABLE_CLASS(klass); |
c5d4dac8 GH |
224 | |
225 | set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); | |
4f67d30b | 226 | device_class_set_props(dc, virtio_vga_base_properties); |
c68082c4 | 227 | dc->vmsd = &vmstate_virtio_vga_base; |
c5d4dac8 | 228 | dc->hotpluggable = false; |
0d898904 PM |
229 | resettable_class_set_parent_phases(rc, NULL, virtio_vga_base_reset_hold, |
230 | NULL, &v->parent_phases); | |
c5d4dac8 | 231 | |
c68082c4 | 232 | k->realize = virtio_vga_base_realize; |
c5d4dac8 GH |
233 | pcidev_k->romfile = "vgabios-virtio.bin"; |
234 | pcidev_k->class_id = PCI_CLASS_DISPLAY_VGA; | |
8be61ce2 GH |
235 | |
236 | /* Expose framebuffer byteorder via QOM */ | |
237 | object_class_property_add_bool(klass, "big-endian-framebuffer", | |
238 | virtio_vga_get_big_endian_fb, | |
239 | virtio_vga_set_big_endian_fb); | |
c5d4dac8 GH |
240 | } |
241 | ||
5e78c98b | 242 | static const TypeInfo virtio_vga_base_info = { |
c68082c4 MAL |
243 | .name = TYPE_VIRTIO_VGA_BASE, |
244 | .parent = TYPE_VIRTIO_PCI, | |
b84bf23c EH |
245 | .instance_size = sizeof(VirtIOVGABase), |
246 | .class_size = sizeof(VirtIOVGABaseClass), | |
c68082c4 MAL |
247 | .class_init = virtio_vga_base_class_init, |
248 | .abstract = true, | |
249 | }; | |
561d0f45 | 250 | module_obj(TYPE_VIRTIO_VGA_BASE); |
24ce7aa7 | 251 | module_kconfig(VIRTIO_VGA); |
c68082c4 MAL |
252 | |
253 | #define TYPE_VIRTIO_VGA "virtio-vga" | |
254 | ||
db1015e9 | 255 | typedef struct VirtIOVGA VirtIOVGA; |
8110fa1d EH |
256 | DECLARE_INSTANCE_CHECKER(VirtIOVGA, VIRTIO_VGA, |
257 | TYPE_VIRTIO_VGA) | |
c68082c4 | 258 | |
db1015e9 | 259 | struct VirtIOVGA { |
c68082c4 MAL |
260 | VirtIOVGABase parent_obj; |
261 | ||
262 | VirtIOGPU vdev; | |
db1015e9 | 263 | }; |
c68082c4 | 264 | |
c5d4dac8 GH |
265 | static void virtio_vga_inst_initfn(Object *obj) |
266 | { | |
267 | VirtIOVGA *dev = VIRTIO_VGA(obj); | |
b3409a31 GH |
268 | |
269 | virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), | |
270 | TYPE_VIRTIO_GPU); | |
c68082c4 | 271 | VIRTIO_VGA_BASE(dev)->vgpu = VIRTIO_GPU_BASE(&dev->vdev); |
c5d4dac8 GH |
272 | } |
273 | ||
c68082c4 | 274 | |
a4ee4c8b EH |
275 | static VirtioPCIDeviceTypeInfo virtio_vga_info = { |
276 | .generic_name = TYPE_VIRTIO_VGA, | |
c68082c4 | 277 | .parent = TYPE_VIRTIO_VGA_BASE, |
b84bf23c | 278 | .instance_size = sizeof(VirtIOVGA), |
c5d4dac8 | 279 | .instance_init = virtio_vga_inst_initfn, |
c5d4dac8 | 280 | }; |
561d0f45 | 281 | module_obj(TYPE_VIRTIO_VGA); |
c5d4dac8 GH |
282 | |
283 | static void virtio_vga_register_types(void) | |
284 | { | |
c68082c4 | 285 | type_register_static(&virtio_vga_base_info); |
a4ee4c8b | 286 | virtio_pci_types_register(&virtio_vga_info); |
c5d4dac8 GH |
287 | } |
288 | ||
289 | type_init(virtio_vga_register_types) |