master
c 1,927 lines 60.8 KB
Raw
1 /*
2 * Virtio GPU Device
3 *
4 * Copyright Red Hat, Inc. 2013-2014
5 *
6 * Authors:
7 * Dave Airlie <airlied@redhat.com>
8 * Gerd Hoffmann <kraxel@redhat.com>
9 *
10 * This work is licensed under the terms of the GNU GPL, version 2 or later.
11 * See the COPYING file in the top-level directory.
12 */
13
14 #include "qemu/osdep.h"
15 #include "qemu/units.h"
16 #include "qemu/iov.h"
17 #include "system/cpus.h"
18 #include "ui/console.h"
19 #include "ui/rect.h"
20 #include "trace.h"
21 #include "system/dma.h"
22 #include "system/system.h"
23 #include "hw/virtio/virtio.h"
24 #include "migration/qemu-file-types.h"
25 #include "hw/virtio/virtio-gpu.h"
26 #include "hw/virtio/virtio-gpu-bswap.h"
27 #include "hw/virtio/virtio-gpu-pixman.h"
28 #include "hw/virtio/virtio-bus.h"
29 #include "hw/core/qdev-properties.h"
30 #include "qemu/log.h"
31 #include "qemu/memfd.h"
32 #include "qemu/module.h"
33 #include "qapi/error.h"
34 #include "qemu/error-report.h"
35
36 #define VIRTIO_GPU_VM_VERSION 1
37
38 static struct virtio_gpu_simple_resource *
39 virtio_gpu_find_check_resource(VirtIOGPU *g, uint32_t resource_id,
40 const char *caller, uint32_t *error);
41
42 static void virtio_gpu_reset_bh(void *opaque);
43
44 void virtio_gpu_update_cursor_data(VirtIOGPU *g,
45 struct virtio_gpu_scanout *s,
46 uint32_t resource_id)
47 {
48 struct virtio_gpu_simple_resource *res;
49 uint32_t pixels;
50 void *data;
51
52 res = virtio_gpu_find_check_resource(g, resource_id, __func__, NULL);
53 if (!res) {
54 return;
55 }
56
57 if (res->image) {
58 if (pixman_image_get_width(res->image) != s->current_cursor->width ||
59 pixman_image_get_height(res->image) != s->current_cursor->height) {
60 return;
61 }
62 data = pixman_image_get_data(res->image);
63 } else {
64 if (!res->iov || res->blob_size < (s->current_cursor->width *
65 s->current_cursor->height * 4)) {
66 return;
67 }
68 data = res->blob;
69 }
70
71 pixels = s->current_cursor->width * s->current_cursor->height;
72 memcpy(s->current_cursor->data, data,
73 pixels * sizeof(uint32_t));
74 }
75
76 static void update_cursor(VirtIOGPU *g, struct virtio_gpu_update_cursor *cursor)
77 {
78 struct virtio_gpu_scanout *s;
79 VirtIOGPUClass *vgc = VIRTIO_GPU_GET_CLASS(g);
80 bool move = cursor->hdr.type == VIRTIO_GPU_CMD_MOVE_CURSOR;
81
82 if (cursor->pos.scanout_id >= g->parent_obj.conf.max_outputs) {
83 return;
84 }
85 s = &g->parent_obj.scanout[cursor->pos.scanout_id];
86
87 trace_virtio_gpu_update_cursor(cursor->pos.scanout_id,
88 cursor->pos.x,
89 cursor->pos.y,
90 move ? "move" : "update",
91 cursor->resource_id);
92
93 if (!move) {
94 if (!s->current_cursor) {
95 s->current_cursor = cursor_alloc(64, 64);
96 }
97
98 s->current_cursor->hot_x = cursor->hot_x;
99 s->current_cursor->hot_y = cursor->hot_y;
100
101 if (cursor->resource_id > 0) {
102 vgc->update_cursor_data(g, s, cursor->resource_id);
103 }
104 qemu_console_set_cursor(s->con, s->current_cursor);
105
106 s->cursor = *cursor;
107 } else {
108 s->cursor.pos.x = cursor->pos.x;
109 s->cursor.pos.y = cursor->pos.y;
110 }
111 qemu_console_set_mouse(s->con, cursor->pos.x, cursor->pos.y, cursor->resource_id);
112 }
113
114 struct virtio_gpu_simple_resource *
115 virtio_gpu_find_resource(VirtIOGPU *g, uint32_t resource_id)
116 {
117 struct virtio_gpu_simple_resource *res;
118
119 QTAILQ_FOREACH(res, &g->reslist, next) {
120 if (res->resource_id == resource_id) {
121 return res;
122 }
123 }
124 return NULL;
125 }
126
127 static struct virtio_gpu_simple_resource *
128 virtio_gpu_find_check_resource(VirtIOGPU *g, uint32_t resource_id,
129 const char *caller, uint32_t *error)
130 {
131 struct virtio_gpu_simple_resource *res;
132
133 res = virtio_gpu_find_resource(g, resource_id);
134 if (!res) {
135 qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid resource specified %d\n",
136 caller, resource_id);
137 if (error) {
138 *error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
139 }
140 return NULL;
141 }
142
143 return res;
144 }
145
146 void virtio_gpu_ctrl_response(VirtIOGPU *g,
147 struct virtio_gpu_ctrl_command *cmd,
148 struct virtio_gpu_ctrl_hdr *resp,
149 size_t resp_len)
150 {
151 size_t s;
152
153 if (cmd->cmd_hdr.flags & VIRTIO_GPU_FLAG_FENCE) {
154 resp->flags |= VIRTIO_GPU_FLAG_FENCE;
155 resp->fence_id = cmd->cmd_hdr.fence_id;
156 resp->ctx_id = cmd->cmd_hdr.ctx_id;
157 }
158 virtio_gpu_ctrl_hdr_bswap(resp);
159 s = iov_from_buf(cmd->elem.in_sg, cmd->elem.in_num, 0, resp, resp_len);
160 if (s != resp_len) {
161 qemu_log_mask(LOG_GUEST_ERROR,
162 "%s: response size incorrect %zu vs %zu\n",
163 __func__, s, resp_len);
164 }
165 virtqueue_push(cmd->vq, &cmd->elem, s);
166 virtio_notify(VIRTIO_DEVICE(g), cmd->vq);
167 cmd->finished = true;
168 }
169
170 void virtio_gpu_ctrl_response_nodata(VirtIOGPU *g,
171 struct virtio_gpu_ctrl_command *cmd,
172 enum virtio_gpu_ctrl_type type)
173 {
174 struct virtio_gpu_ctrl_hdr resp;
175
176 memset(&resp, 0, sizeof(resp));
177 resp.type = type;
178 virtio_gpu_ctrl_response(g, cmd, &resp, sizeof(resp));
179 }
180
181 void virtio_gpu_get_display_info(VirtIOGPU *g,
182 struct virtio_gpu_ctrl_command *cmd)
183 {
184 struct virtio_gpu_resp_display_info display_info;
185
186 trace_virtio_gpu_cmd_get_display_info();
187 memset(&display_info, 0, sizeof(display_info));
188 display_info.hdr.type = VIRTIO_GPU_RESP_OK_DISPLAY_INFO;
189 virtio_gpu_base_fill_display_info(VIRTIO_GPU_BASE(g), &display_info);
190 virtio_gpu_ctrl_response(g, cmd, &display_info.hdr,
191 sizeof(display_info));
192 }
193
194 void virtio_gpu_get_edid(VirtIOGPU *g,
195 struct virtio_gpu_ctrl_command *cmd)
196 {
197 struct virtio_gpu_resp_edid edid;
198 struct virtio_gpu_cmd_get_edid get_edid;
199 VirtIOGPUBase *b = VIRTIO_GPU_BASE(g);
200
201 VIRTIO_GPU_FILL_CMD(get_edid);
202 virtio_gpu_bswap_32(&get_edid, sizeof(get_edid));
203
204 if (get_edid.scanout >= b->conf.max_outputs) {
205 cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
206 return;
207 }
208
209 trace_virtio_gpu_cmd_get_edid(get_edid.scanout);
210 memset(&edid, 0, sizeof(edid));
211 edid.hdr.type = VIRTIO_GPU_RESP_OK_EDID;
212 virtio_gpu_base_generate_edid(VIRTIO_GPU_BASE(g), get_edid.scanout, &edid);
213 virtio_gpu_ctrl_response(g, cmd, &edid.hdr, sizeof(edid));
214 }
215
216 static bool calc_image_hostmem(pixman_format_code_t pformat,
217 uint32_t width, uint32_t height,
218 uint32_t *hostmem, uint32_t *rowstride_bytes)
219 {
220 uint64_t bpp = PIXMAN_FORMAT_BPP(pformat);
221 uint64_t stride = (((uint64_t)width * bpp + 0x1f) >> 5) * sizeof(uint32_t);
222 uint64_t size = (uint64_t)height * stride;
223
224 if (size > UINT32_MAX) {
225 return false;
226 }
227
228 *hostmem = size;
229 *rowstride_bytes = stride;
230 return true;
231 }
232
233 static void virtio_gpu_resource_create_2d(VirtIOGPU *g,
234 struct virtio_gpu_ctrl_command *cmd)
235 {
236 Error *err = NULL;
237 pixman_format_code_t pformat;
238 struct virtio_gpu_simple_resource *res;
239 struct virtio_gpu_resource_create_2d c2d;
240 uint32_t hostmem, rowstride_bytes;
241
242 VIRTIO_GPU_FILL_CMD(c2d);
243 virtio_gpu_bswap_32(&c2d, sizeof(c2d));
244 trace_virtio_gpu_cmd_res_create_2d(c2d.resource_id, c2d.format,
245 c2d.width, c2d.height);
246
247 if (c2d.resource_id == 0) {
248 qemu_log_mask(LOG_GUEST_ERROR, "%s: resource id 0 is not allowed\n",
249 __func__);
250 cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
251 return;
252 }
253
254 res = virtio_gpu_find_resource(g, c2d.resource_id);
255 if (res) {
256 qemu_log_mask(LOG_GUEST_ERROR, "%s: resource already exists %d\n",
257 __func__, c2d.resource_id);
258 cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
259 return;
260 }
261
262 res = g_new0(struct virtio_gpu_simple_resource, 1);
263
264 res->width = c2d.width;
265 res->height = c2d.height;
266 res->format = c2d.format;
267 res->resource_id = c2d.resource_id;
268
269 pformat = virtio_gpu_get_pixman_format(c2d.format);
270 if (!pformat) {
271 qemu_log_mask(LOG_GUEST_ERROR,
272 "%s: host couldn't handle guest format %d\n",
273 __func__, c2d.format);
274 g_free(res);
275 cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
276 return;
277 }
278
279 if (!calc_image_hostmem(pformat, c2d.width, c2d.height,
280 &hostmem, &rowstride_bytes)) {
281 qemu_log_mask(LOG_GUEST_ERROR, "%s: image dimensions overflow\n",
282 __func__);
283 goto end;
284 }
285 res->hostmem = hostmem;
286 if (res->hostmem + g->hostmem < g->conf_max_hostmem) {
287 if (!qemu_pixman_image_new_shareable(
288 &res->image,
289 &res->share_handle,
290 "virtio-gpu res",
291 pformat,
292 c2d.width,
293 c2d.height,
294 rowstride_bytes,
295 &err)) {
296 warn_report_err(err);
297 goto end;
298 }
299 }
300
301 end:
302 if (!res->image) {
303 qemu_log_mask(LOG_GUEST_ERROR,
304 "%s: resource creation failed %d %d %d\n",
305 __func__, c2d.resource_id, c2d.width, c2d.height);
306 g_free(res);
307 cmd->error = VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY;
308 return;
309 }
310
311 QTAILQ_INSERT_HEAD(&g->reslist, res, next);
312 g->hostmem += res->hostmem;
313 }
314
315 static void virtio_gpu_resource_create_blob(VirtIOGPU *g,
316 struct virtio_gpu_ctrl_command *cmd)
317 {
318 struct virtio_gpu_simple_resource *res;
319 struct virtio_gpu_resource_create_blob cblob;
320 int ret;
321
322 VIRTIO_GPU_FILL_CMD(cblob);
323 virtio_gpu_create_blob_bswap(&cblob);
324 trace_virtio_gpu_cmd_res_create_blob(cblob.resource_id, cblob.size);
325
326 if (cblob.resource_id == 0) {
327 qemu_log_mask(LOG_GUEST_ERROR, "%s: resource id 0 is not allowed\n",
328 __func__);
329 cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
330 return;
331 }
332
333 if (cblob.blob_mem != VIRTIO_GPU_BLOB_MEM_GUEST &&
334 cblob.blob_flags != VIRTIO_GPU_BLOB_FLAG_USE_SHAREABLE) {
335 qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid memory type\n",
336 __func__);
337 cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
338 return;
339 }
340
341 if (virtio_gpu_find_resource(g, cblob.resource_id)) {
342 qemu_log_mask(LOG_GUEST_ERROR, "%s: resource already exists %d\n",
343 __func__, cblob.resource_id);
344 cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
345 return;
346 }
347
348 res = g_new0(struct virtio_gpu_simple_resource, 1);
349 res->resource_id = cblob.resource_id;
350 res->blob_size = cblob.size;
351
352 if (cblob.nr_entries) {
353 ret = virtio_gpu_create_mapping_iov(g, cblob.nr_entries, sizeof(cblob),
354 cmd, &res->addrs, &res->iov,
355 &res->iov_cnt);
356 if (ret < 0) {
357 cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
358 g_free(res);
359 return;
360 }
361
362 if (iov_size(res->iov, res->iov_cnt) < res->blob_size) {
363 qemu_log_mask(LOG_GUEST_ERROR,
364 "%s: backing storage smaller than blob size\n",
365 __func__);
366 cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
367 virtio_gpu_cleanup_mapping(g, res);
368 g_free(res);
369 return;
370 }
371
372 if (!virtio_gpu_init_udmabuf(res)) {
373 cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
374 virtio_gpu_cleanup_mapping(g, res);
375 g_free(res);
376 return;
377 }
378 }
379
380 QTAILQ_INSERT_HEAD(&g->reslist, res, next);
381 }
382
383 void virtio_gpu_disable_scanout(VirtIOGPU *g, int scanout_id)
384 {
385 struct virtio_gpu_scanout *scanout = &g->parent_obj.scanout[scanout_id];
386 struct virtio_gpu_simple_resource *res;
387
388 if (scanout->resource_id == 0) {
389 return;
390 }
391
392 res = virtio_gpu_find_resource(g, scanout->resource_id);
393 if (res) {
394 res->scanout_bitmask &= ~(1 << scanout_id);
395 }
396
397 qemu_console_set_surface(scanout->con, NULL);
398 scanout->resource_id = 0;
399 scanout->ds = NULL;
400 scanout->width = 0;
401 scanout->height = 0;
402 }
403
404 static void virtio_gpu_resource_destroy(VirtIOGPU *g,
405 struct virtio_gpu_simple_resource *res,
406 Error **errp)
407 {
408 int i;
409
410 if (res->scanout_bitmask) {
411 for (i = 0; i < g->parent_obj.conf.max_outputs; i++) {
412 if (res->scanout_bitmask & (1 << i)) {
413 virtio_gpu_disable_scanout(g, i);
414 }
415 }
416 }
417
418 qemu_pixman_image_unref(res->image);
419 virtio_gpu_cleanup_mapping(g, res);
420 QTAILQ_REMOVE(&g->reslist, res, next);
421 g->hostmem -= res->hostmem;
422 g_free(res);
423 }
424
425 static void virtio_gpu_resource_unref(VirtIOGPU *g,
426 struct virtio_gpu_ctrl_command *cmd)
427 {
428 struct virtio_gpu_simple_resource *res;
429 struct virtio_gpu_resource_unref unref;
430
431 VIRTIO_GPU_FILL_CMD(unref);
432 virtio_gpu_bswap_32(&unref, sizeof(unref));
433 trace_virtio_gpu_cmd_res_unref(unref.resource_id);
434
435 res = virtio_gpu_find_resource(g, unref.resource_id);
436 if (!res) {
437 qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal resource specified %d\n",
438 __func__, unref.resource_id);
439 cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
440 return;
441 }
442 /*
443 * virtio_gpu_resource_destroy does not set any errors, so pass a NULL errp
444 * to ignore them.
445 */
446 virtio_gpu_resource_destroy(g, res, NULL);
447 }
448
449 static void virtio_gpu_transfer_to_host_2d(VirtIOGPU *g,
450 struct virtio_gpu_ctrl_command *cmd)
451 {
452 struct virtio_gpu_simple_resource *res;
453 int h, bpp;
454 uint32_t src_offset, dst_offset, stride;
455 pixman_format_code_t format;
456 struct virtio_gpu_transfer_to_host_2d t2d;
457 void *img_data;
458
459 VIRTIO_GPU_FILL_CMD(t2d);
460 virtio_gpu_t2d_bswap(&t2d);
461 trace_virtio_gpu_cmd_res_xfer_toh_2d(t2d.resource_id);
462
463 res = virtio_gpu_find_check_resource(g, t2d.resource_id,
464 __func__, &cmd->error);
465 if (!res) {
466 return;
467 }
468
469 if (!res->image) {
470 qemu_log_mask(LOG_GUEST_ERROR, "%s: resource %d is a blob\n",
471 __func__, t2d.resource_id);
472 cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
473 return;
474 }
475
476 if (!res->iov) {
477 qemu_log_mask(LOG_GUEST_ERROR,
478 "%s: resource %d has no backing storage\n",
479 __func__, t2d.resource_id);
480 cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
481 return;
482 }
483
484 if (t2d.r.x > res->width ||
485 t2d.r.y > res->height ||
486 t2d.r.width > res->width ||
487 t2d.r.height > res->height ||
488 t2d.r.x + t2d.r.width > res->width ||
489 t2d.r.y + t2d.r.height > res->height) {
490 qemu_log_mask(LOG_GUEST_ERROR, "%s: transfer bounds outside resource"
491 " bounds for resource %d: %d %d %d %d vs %d %d\n",
492 __func__, t2d.resource_id, t2d.r.x, t2d.r.y,
493 t2d.r.width, t2d.r.height, res->width, res->height);
494 cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
495 return;
496 }
497
498 format = pixman_image_get_format(res->image);
499 bpp = DIV_ROUND_UP(PIXMAN_FORMAT_BPP(format), 8);
500 stride = pixman_image_get_stride(res->image);
501 img_data = pixman_image_get_data(res->image);
502
503 if (t2d.r.x || t2d.r.width != pixman_image_get_width(res->image)) {
504 for (h = 0; h < t2d.r.height; h++) {
505 src_offset = t2d.offset + stride * h;
506 dst_offset = (t2d.r.y + h) * stride + (t2d.r.x * bpp);
507
508 iov_to_buf(res->iov, res->iov_cnt, src_offset,
509 (uint8_t *)img_data + dst_offset,
510 t2d.r.width * bpp);
511 }
512 } else {
513 src_offset = t2d.offset;
514 dst_offset = t2d.r.y * stride + t2d.r.x * bpp;
515 iov_to_buf(res->iov, res->iov_cnt, src_offset,
516 (uint8_t *)img_data + dst_offset,
517 stride * t2d.r.height);
518 }
519 }
520
521 static void virtio_gpu_resource_flush(VirtIOGPU *g,
522 struct virtio_gpu_ctrl_command *cmd)
523 {
524 struct virtio_gpu_simple_resource *res;
525 struct virtio_gpu_resource_flush rf;
526 struct virtio_gpu_scanout *scanout;
527 QemuRect flush_rect;
528 bool within_bounds = false;
529 bool update_submitted = false;
530 int i;
531
532 VIRTIO_GPU_FILL_CMD(rf);
533 virtio_gpu_bswap_32(&rf, sizeof(rf));
534 trace_virtio_gpu_cmd_res_flush(rf.resource_id,
535 rf.r.width, rf.r.height, rf.r.x, rf.r.y);
536
537 res = virtio_gpu_find_check_resource(g, rf.resource_id,
538 __func__, &cmd->error);
539 if (!res) {
540 return;
541 }
542
543 if (res->blob) {
544 for (i = 0; i < g->parent_obj.conf.max_outputs; i++) {
545 scanout = &g->parent_obj.scanout[i];
546 if (scanout->resource_id == res->resource_id &&
547 rf.r.x < scanout->x + scanout->width &&
548 rf.r.x + rf.r.width >= scanout->x &&
549 rf.r.y < scanout->y + scanout->height &&
550 rf.r.y + rf.r.height >= scanout->y) {
551 within_bounds = true;
552
553 if (qemu_console_has_gl(scanout->con)) {
554 qemu_console_gl_update(scanout->con, 0, 0, scanout->width,
555 scanout->height);
556 update_submitted = true;
557 }
558 }
559 }
560
561 if (update_submitted) {
562 return;
563 }
564 if (!within_bounds) {
565 qemu_log_mask(LOG_GUEST_ERROR, "%s: flush bounds outside scanouts"
566 " bounds for flush %d: %d %d %d %d\n",
567 __func__, rf.resource_id, rf.r.x, rf.r.y,
568 rf.r.width, rf.r.height);
569 cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
570 return;
571 }
572 }
573
574 if (!res->blob &&
575 (rf.r.x > res->width ||
576 rf.r.y > res->height ||
577 rf.r.width > res->width ||
578 rf.r.height > res->height ||
579 rf.r.x + rf.r.width > res->width ||
580 rf.r.y + rf.r.height > res->height)) {
581 qemu_log_mask(LOG_GUEST_ERROR, "%s: flush bounds outside resource"
582 " bounds for resource %d: %d %d %d %d vs %d %d\n",
583 __func__, rf.resource_id, rf.r.x, rf.r.y,
584 rf.r.width, rf.r.height, res->width, res->height);
585 cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
586 return;
587 }
588
589 qemu_rect_init(&flush_rect, rf.r.x, rf.r.y, rf.r.width, rf.r.height);
590 for (i = 0; i < g->parent_obj.conf.max_outputs; i++) {
591 QemuRect rect;
592
593 if (!(res->scanout_bitmask & (1 << i))) {
594 continue;
595 }
596 scanout = &g->parent_obj.scanout[i];
597
598 qemu_rect_init(&rect, scanout->x, scanout->y,
599 scanout->width, scanout->height);
600
601 /* work out the area we need to update for each console */
602 if (qemu_rect_intersect(&flush_rect, &rect, &rect)) {
603 qemu_rect_translate(&rect, -scanout->x, -scanout->y);
604 qemu_console_update(g->parent_obj.scanout[i].con,
605 rect.x, rect.y, rect.width, rect.height);
606 }
607 }
608 }
609
610 static void virtio_unref_resource(pixman_image_t *image, void *data)
611 {
612 pixman_image_unref(data);
613 }
614
615 void virtio_gpu_update_scanout(VirtIOGPU *g,
616 uint32_t scanout_id,
617 struct virtio_gpu_simple_resource *res,
618 struct virtio_gpu_framebuffer *fb,
619 struct virtio_gpu_rect *r)
620 {
621 struct virtio_gpu_simple_resource *ores;
622 struct virtio_gpu_scanout *scanout;
623
624 scanout = &g->parent_obj.scanout[scanout_id];
625 ores = virtio_gpu_find_resource(g, scanout->resource_id);
626 if (ores) {
627 ores->scanout_bitmask &= ~(1 << scanout_id);
628 }
629
630 res->scanout_bitmask |= (1 << scanout_id);
631 scanout->resource_id = res->resource_id;
632 scanout->x = r->x;
633 scanout->y = r->y;
634 scanout->width = r->width;
635 scanout->height = r->height;
636 scanout->fb = *fb;
637 }
638
639 static uint32_t virtio_gpu_format_bytes_pp(pixman_format_code_t format)
640 {
641 return DIV_ROUND_UP(PIXMAN_FORMAT_BPP(format), 8);
642 }
643
644 bool virtio_gpu_check_scanout_bounds(uint32_t scanout_id, uint32_t resource_id,
645 uint32_t width, uint32_t height,
646 const struct virtio_gpu_rect *r,
647 uint32_t *error)
648 {
649 if (r->width < 16 ||
650 r->height < 16 ||
651 (uint64_t)r->x + r->width > width ||
652 (uint64_t)r->y + r->height > height) {
653 qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal scanout %d bounds for"
654 " resource %d, fb %d %d, rect (%d,%d)+%d,%d\n",
655 __func__, scanout_id, resource_id, width, height,
656 r->x, r->y, r->width, r->height);
657 *error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
658 return false;
659 }
660
661 return true;
662 }
663
664 static bool virtio_gpu_do_set_scanout(VirtIOGPU *g,
665 uint32_t scanout_id,
666 struct virtio_gpu_framebuffer *fb,
667 struct virtio_gpu_simple_resource *res,
668 struct virtio_gpu_rect *r,
669 uint32_t *error)
670 {
671 struct virtio_gpu_scanout *scanout;
672 uint32_t bytes_pp = virtio_gpu_format_bytes_pp(fb->format);
673 uint8_t *data;
674
675 scanout = &g->parent_obj.scanout[scanout_id];
676
677 if (!virtio_gpu_check_scanout_bounds(scanout_id, res->resource_id,
678 fb->width, fb->height, r, error)) {
679 return false;
680 }
681
682 if (fb->stride < (uint64_t)fb->width * bytes_pp) {
683 qemu_log_mask(LOG_GUEST_ERROR,
684 "%s: stride %u too small for width %u at %u bpp\n",
685 __func__, fb->stride, fb->width, bytes_pp);
686 *error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
687 return false;
688 }
689
690 if (fb->stride > INT_MAX) {
691 qemu_log_mask(LOG_GUEST_ERROR, "%s: stride is %" PRIu32
692 ", larger than the supported maximum (%d)\n",
693 __func__, fb->stride, INT_MAX);
694 *error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
695 return false;
696 }
697
698 g->parent_obj.enable = 1;
699
700 if (res->blob) {
701 if (qemu_console_has_gl(scanout->con)) {
702 if (!virtio_gpu_update_dmabuf(g, scanout_id, res, fb, r)) {
703 virtio_gpu_update_scanout(g, scanout_id, res, fb, r);
704 } else {
705 *error = VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY;
706 return false;
707 }
708 return true;
709 }
710
711 data = res->blob;
712 } else {
713 data = (uint8_t *)pixman_image_get_data(res->image);
714 }
715
716 /* create a surface for this scanout */
717 if ((res->blob && !qemu_console_has_gl(scanout->con)) ||
718 !scanout->ds ||
719 surface_data(scanout->ds) != data + fb->offset ||
720 scanout->width != r->width ||
721 scanout->height != r->height) {
722 pixman_image_t *rect;
723 void *ptr = data + fb->offset;
724 rect = pixman_image_create_bits(fb->format, r->width, r->height,
725 ptr, fb->stride);
726 if (!rect) {
727 *error = VIRTIO_GPU_RESP_ERR_UNSPEC;
728 return false;
729 }
730
731 if (res->image) {
732 pixman_image_ref(res->image);
733 pixman_image_set_destroy_function(rect, virtio_unref_resource,
734 res->image);
735 }
736
737 /* realloc the surface ptr */
738 scanout->ds = qemu_create_displaysurface_pixman(rect);
739 qemu_displaysurface_set_share_handle(scanout->ds, res->share_handle, fb->offset);
740
741 pixman_image_unref(rect);
742 qemu_console_set_surface(g->parent_obj.scanout[scanout_id].con,
743 scanout->ds);
744 }
745
746 virtio_gpu_update_scanout(g, scanout_id, res, fb, r);
747 return true;
748 }
749
750 static void virtio_gpu_set_scanout(VirtIOGPU *g,
751 struct virtio_gpu_ctrl_command *cmd)
752 {
753 struct virtio_gpu_simple_resource *res;
754 struct virtio_gpu_framebuffer fb = { 0 };
755 struct virtio_gpu_set_scanout ss;
756 uint32_t bytes_pp;
757
758 VIRTIO_GPU_FILL_CMD(ss);
759 virtio_gpu_bswap_32(&ss, sizeof(ss));
760 trace_virtio_gpu_cmd_set_scanout(ss.scanout_id, ss.resource_id,
761 ss.r.width, ss.r.height, ss.r.x, ss.r.y);
762
763 if (ss.scanout_id >= g->parent_obj.conf.max_outputs) {
764 qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal scanout id specified %d",
765 __func__, ss.scanout_id);
766 cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID;
767 return;
768 }
769
770 if (ss.resource_id == 0) {
771 virtio_gpu_disable_scanout(g, ss.scanout_id);
772 return;
773 }
774
775 res = virtio_gpu_find_check_resource(g, ss.resource_id,
776 __func__, &cmd->error);
777 if (!res) {
778 return;
779 }
780
781 if (!res->image) {
782 qemu_log_mask(LOG_GUEST_ERROR, "%s: resource %d is a blob\n",
783 __func__, ss.resource_id);
784 cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
785 return;
786 }
787
788 fb.format = pixman_image_get_format(res->image);
789 bytes_pp = virtio_gpu_format_bytes_pp(fb.format);
790 fb.width = pixman_image_get_width(res->image);
791 fb.height = pixman_image_get_height(res->image);
792 fb.stride = pixman_image_get_stride(res->image);
793 fb.offset = ss.r.x * bytes_pp + ss.r.y * fb.stride;
794
795 virtio_gpu_do_set_scanout(g, ss.scanout_id,
796 &fb, res, &ss.r, &cmd->error);
797 }
798
799 bool virtio_gpu_scanout_blob_to_fb(struct virtio_gpu_framebuffer *fb,
800 struct virtio_gpu_set_scanout_blob *ss,
801 uint64_t blob_size)
802 {
803 uint64_t fbend, offset;
804 uint32_t bytes_pp;
805
806 fb->format = virtio_gpu_get_pixman_format(ss->format);
807 if (!fb->format) {
808 qemu_log_mask(LOG_GUEST_ERROR,
809 "%s: host couldn't handle guest format %d\n",
810 __func__, ss->format);
811 return false;
812 }
813
814 bytes_pp = virtio_gpu_format_bytes_pp(fb->format);
815 fb->width = ss->width;
816 fb->height = ss->height;
817 fb->stride = ss->strides[0];
818
819 if (fb->stride < (uint64_t)fb->width * bytes_pp) {
820 qemu_log_mask(LOG_GUEST_ERROR,
821 "%s: stride %u too small for width %u at %u bpp\n",
822 __func__, fb->stride, fb->width, bytes_pp);
823 return false;
824 }
825
826 if (fb->stride > INT_MAX) {
827 qemu_log_mask(LOG_GUEST_ERROR, "%s: stride is %" PRIu32
828 ", larger than the supported maximum (%d)\n",
829 __func__, fb->stride, INT_MAX);
830 return false;
831 }
832
833 offset = (uint64_t)ss->offsets[0] + (uint64_t)ss->r.x * bytes_pp +
834 (uint64_t)ss->r.y * fb->stride;
835
836 fbend = offset + (uint64_t)fb->stride * ss->r.height;
837
838 if (offset > UINT32_MAX || fbend > blob_size) {
839 qemu_log_mask(LOG_GUEST_ERROR,
840 "%s: invalid fb bounds\n",
841 __func__);
842 return false;
843 }
844
845 fb->offset = offset;
846
847 return true;
848 }
849
850
851
852 static void virtio_gpu_set_scanout_blob(VirtIOGPU *g,
853 struct virtio_gpu_ctrl_command *cmd)
854 {
855 struct virtio_gpu_simple_resource *res;
856 struct virtio_gpu_framebuffer fb = { 0 };
857 struct virtio_gpu_set_scanout_blob ss;
858
859 VIRTIO_GPU_FILL_CMD(ss);
860 virtio_gpu_scanout_blob_bswap(&ss);
861 trace_virtio_gpu_cmd_set_scanout_blob(ss.scanout_id, ss.resource_id,
862 ss.r.width, ss.r.height, ss.r.x,
863 ss.r.y);
864
865 if (ss.scanout_id >= g->parent_obj.conf.max_outputs) {
866 qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal scanout id specified %d",
867 __func__, ss.scanout_id);
868 cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID;
869 return;
870 }
871
872 if (ss.resource_id == 0) {
873 virtio_gpu_disable_scanout(g, ss.scanout_id);
874 return;
875 }
876
877 res = virtio_gpu_find_check_resource(g, ss.resource_id,
878 __func__, &cmd->error);
879 if (!res) {
880 return;
881 }
882
883 if (res->image) {
884 qemu_log_mask(LOG_GUEST_ERROR,
885 "%s: resource %d is not a blob\n",
886 __func__, ss.resource_id);
887 cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
888 return;
889 }
890
891 if (!res->iov) {
892 qemu_log_mask(LOG_GUEST_ERROR,
893 "%s: resource %d has no backing storage\n",
894 __func__, ss.resource_id);
895 cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
896 return;
897 }
898
899 if (!virtio_gpu_scanout_blob_to_fb(&fb, &ss, res->blob_size)) {
900 cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
901 return;
902 }
903
904 virtio_gpu_do_set_scanout(g, ss.scanout_id,
905 &fb, res, &ss.r, &cmd->error);
906 }
907
908 int virtio_gpu_create_mapping_iov(VirtIOGPU *g,
909 uint32_t nr_entries, uint32_t offset,
910 struct virtio_gpu_ctrl_command *cmd,
911 uint64_t **addr, struct iovec **iov,
912 uint32_t *niov)
913 {
914 struct virtio_gpu_mem_entry *ents;
915 size_t esize, s;
916 int e, v;
917
918 if (nr_entries > 16384) {
919 qemu_log_mask(LOG_GUEST_ERROR,
920 "%s: nr_entries is too big (%d > 16384)\n",
921 __func__, nr_entries);
922 return -1;
923 }
924
925 esize = sizeof(*ents) * nr_entries;
926 ents = g_try_malloc(esize);
927 if (!ents && esize) {
928 return -1;
929 }
930 s = iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num,
931 offset, ents, esize);
932 if (s != esize) {
933 qemu_log_mask(LOG_GUEST_ERROR,
934 "%s: command data size incorrect %zu vs %zu\n",
935 __func__, s, esize);
936 g_free(ents);
937 return -1;
938 }
939
940 *iov = NULL;
941 if (addr) {
942 *addr = NULL;
943 }
944 for (e = 0, v = 0; e < nr_entries; e++) {
945 uint64_t a = le64_to_cpu(ents[e].addr);
946 uint32_t l = le32_to_cpu(ents[e].length);
947 hwaddr len;
948 void *map;
949
950 /* TODO: a common DMA map SG helper */
951 do {
952 len = l;
953 map = dma_memory_map(VIRTIO_DEVICE(g)->dma_as, a, &len,
954 DMA_DIRECTION_TO_DEVICE,
955 MEMTXATTRS_UNSPECIFIED);
956 if (!map) {
957 qemu_log_mask(LOG_GUEST_ERROR, "%s: failed to map MMIO memory for"
958 " element %d\n", __func__, e);
959 goto err;
960 }
961
962 if (!(v % 16)) {
963 struct iovec *new_iov;
964 new_iov = g_try_renew(struct iovec, *iov, v + 16);
965 if (!new_iov) {
966 dma_memory_unmap(VIRTIO_DEVICE(g)->dma_as, map, len,
967 DMA_DIRECTION_TO_DEVICE, len);
968 goto err;
969 }
970 *iov = new_iov;
971 if (addr) {
972 uint64_t *new_addr;
973 new_addr = g_try_renew(uint64_t, *addr, v + 16);
974 if (!new_addr) {
975 dma_memory_unmap(VIRTIO_DEVICE(g)->dma_as, map, len,
976 DMA_DIRECTION_TO_DEVICE, len);
977 goto err;
978 }
979 *addr = new_addr;
980 }
981 }
982 (*iov)[v].iov_base = map;
983 (*iov)[v].iov_len = len;
984 if (addr) {
985 (*addr)[v] = a;
986 }
987
988 a += len;
989 l -= len;
990 v += 1;
991 } while (l > 0);
992 }
993 *niov = v;
994
995 g_free(ents);
996 return 0;
997
998 err:
999 virtio_gpu_cleanup_mapping_iov(g, *iov, v);
1000 *iov = NULL;
1001 if (addr) {
1002 g_clear_pointer(addr, g_free);
1003 }
1004 g_free(ents);
1005 return -1;
1006 }
1007
1008 void virtio_gpu_cleanup_mapping_iov(VirtIOGPU *g,
1009 struct iovec *iov, uint32_t count)
1010 {
1011 int i;
1012
1013 for (i = 0; i < count; i++) {
1014 dma_memory_unmap(VIRTIO_DEVICE(g)->dma_as,
1015 iov[i].iov_base, iov[i].iov_len,
1016 DMA_DIRECTION_TO_DEVICE,
1017 iov[i].iov_len);
1018 }
1019 g_free(iov);
1020 }
1021
1022 void virtio_gpu_cleanup_mapping(VirtIOGPU *g,
1023 struct virtio_gpu_simple_resource *res)
1024 {
1025 virtio_gpu_cleanup_mapping_iov(g, res->iov, res->iov_cnt);
1026 res->iov = NULL;
1027 res->iov_cnt = 0;
1028 g_free(res->addrs);
1029 res->addrs = NULL;
1030
1031 if (res->blob) {
1032 virtio_gpu_fini_udmabuf(g, res);
1033 }
1034 }
1035
1036 static void
1037 virtio_gpu_resource_attach_backing(VirtIOGPU *g,
1038 struct virtio_gpu_ctrl_command *cmd)
1039 {
1040 struct virtio_gpu_simple_resource *res;
1041 struct virtio_gpu_resource_attach_backing ab;
1042 int ret;
1043
1044 VIRTIO_GPU_FILL_CMD(ab);
1045 virtio_gpu_bswap_32(&ab, sizeof(ab));
1046 trace_virtio_gpu_cmd_res_back_attach(ab.resource_id);
1047
1048 res = virtio_gpu_find_resource(g, ab.resource_id);
1049 if (!res) {
1050 qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal resource specified %d\n",
1051 __func__, ab.resource_id);
1052 cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
1053 return;
1054 }
1055
1056 if (res->iov) {
1057 cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
1058 return;
1059 }
1060
1061 ret = virtio_gpu_create_mapping_iov(g, ab.nr_entries, sizeof(ab), cmd,
1062 &res->addrs, &res->iov, &res->iov_cnt);
1063 if (ret < 0) {
1064 cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
1065 return;
1066 }
1067
1068 if (iov_size(res->iov, res->iov_cnt) < res->blob_size) {
1069 qemu_log_mask(LOG_GUEST_ERROR,
1070 "%s: backing storage smaller than blob size\n",
1071 __func__);
1072 cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
1073 virtio_gpu_cleanup_mapping(g, res);
1074 return;
1075 }
1076
1077 if (!res->image && !virtio_gpu_init_udmabuf(res)) {
1078 cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
1079 virtio_gpu_cleanup_mapping(g, res);
1080 }
1081 }
1082
1083 static void
1084 virtio_gpu_resource_detach_backing(VirtIOGPU *g,
1085 struct virtio_gpu_ctrl_command *cmd)
1086 {
1087 struct virtio_gpu_simple_resource *res;
1088 struct virtio_gpu_resource_detach_backing detach;
1089
1090 VIRTIO_GPU_FILL_CMD(detach);
1091 virtio_gpu_bswap_32(&detach, sizeof(detach));
1092 trace_virtio_gpu_cmd_res_back_detach(detach.resource_id);
1093
1094 res = virtio_gpu_find_check_resource(g, detach.resource_id,
1095 __func__, &cmd->error);
1096 if (!res) {
1097 return;
1098 }
1099 virtio_gpu_cleanup_mapping(g, res);
1100 }
1101
1102 void virtio_gpu_simple_process_cmd(VirtIOGPU *g,
1103 struct virtio_gpu_ctrl_command *cmd)
1104 {
1105 VIRTIO_GPU_FILL_CMD(cmd->cmd_hdr);
1106 virtio_gpu_ctrl_hdr_bswap(&cmd->cmd_hdr);
1107
1108 switch (cmd->cmd_hdr.type) {
1109 case VIRTIO_GPU_CMD_GET_DISPLAY_INFO:
1110 virtio_gpu_get_display_info(g, cmd);
1111 break;
1112 case VIRTIO_GPU_CMD_GET_EDID:
1113 virtio_gpu_get_edid(g, cmd);
1114 break;
1115 case VIRTIO_GPU_CMD_RESOURCE_CREATE_2D:
1116 virtio_gpu_resource_create_2d(g, cmd);
1117 break;
1118 case VIRTIO_GPU_CMD_RESOURCE_CREATE_BLOB:
1119 if (!virtio_gpu_blob_enabled(g->parent_obj.conf)) {
1120 cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
1121 break;
1122 }
1123 virtio_gpu_resource_create_blob(g, cmd);
1124 break;
1125 case VIRTIO_GPU_CMD_RESOURCE_UNREF:
1126 virtio_gpu_resource_unref(g, cmd);
1127 break;
1128 case VIRTIO_GPU_CMD_RESOURCE_FLUSH:
1129 virtio_gpu_resource_flush(g, cmd);
1130 break;
1131 case VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D:
1132 virtio_gpu_transfer_to_host_2d(g, cmd);
1133 break;
1134 case VIRTIO_GPU_CMD_SET_SCANOUT:
1135 virtio_gpu_set_scanout(g, cmd);
1136 break;
1137 case VIRTIO_GPU_CMD_SET_SCANOUT_BLOB:
1138 if (!virtio_gpu_blob_enabled(g->parent_obj.conf)) {
1139 cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
1140 break;
1141 }
1142 virtio_gpu_set_scanout_blob(g, cmd);
1143 break;
1144 case VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING:
1145 virtio_gpu_resource_attach_backing(g, cmd);
1146 break;
1147 case VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING:
1148 virtio_gpu_resource_detach_backing(g, cmd);
1149 break;
1150 default:
1151 cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
1152 break;
1153 }
1154 if (!cmd->finished) {
1155 if (!g->parent_obj.renderer_blocked) {
1156 virtio_gpu_ctrl_response_nodata(g, cmd, cmd->error ? cmd->error :
1157 VIRTIO_GPU_RESP_OK_NODATA);
1158 }
1159 }
1160 }
1161
1162 static void virtio_gpu_handle_ctrl_cb(VirtIODevice *vdev, VirtQueue *vq)
1163 {
1164 VirtIOGPU *g = VIRTIO_GPU(vdev);
1165 qemu_bh_schedule(g->ctrl_bh);
1166 }
1167
1168 static void virtio_gpu_handle_cursor_cb(VirtIODevice *vdev, VirtQueue *vq)
1169 {
1170 VirtIOGPU *g = VIRTIO_GPU(vdev);
1171 qemu_bh_schedule(g->cursor_bh);
1172 }
1173
1174 void virtio_gpu_process_cmdq(VirtIOGPU *g)
1175 {
1176 struct virtio_gpu_ctrl_command *cmd;
1177 VirtIOGPUClass *vgc = VIRTIO_GPU_GET_CLASS(g);
1178
1179 if (g->processing_cmdq) {
1180 return;
1181 }
1182 g->processing_cmdq = true;
1183 while (!QTAILQ_EMPTY(&g->cmdq)) {
1184 cmd = QTAILQ_FIRST(&g->cmdq);
1185
1186 if (g->parent_obj.renderer_blocked) {
1187 break;
1188 }
1189
1190 /* process command */
1191 vgc->process_cmd(g, cmd);
1192
1193 /* command suspended */
1194 if (!cmd->finished && !(cmd->cmd_hdr.flags & VIRTIO_GPU_FLAG_FENCE)) {
1195 trace_virtio_gpu_cmd_suspended(cmd->cmd_hdr.type);
1196 break;
1197 }
1198
1199 QTAILQ_REMOVE(&g->cmdq, cmd, next);
1200 if (virtio_gpu_stats_enabled(g->parent_obj.conf)) {
1201 g->stats.requests++;
1202 }
1203
1204 if (!cmd->finished) {
1205 QTAILQ_INSERT_TAIL(&g->fenceq, cmd, next);
1206 g->inflight++;
1207 if (virtio_gpu_stats_enabled(g->parent_obj.conf)) {
1208 if (g->stats.max_inflight < g->inflight) {
1209 g->stats.max_inflight = g->inflight;
1210 }
1211 trace_virtio_gpu_inc_inflight_fences(g->inflight);
1212 }
1213 } else {
1214 g_free(cmd);
1215 }
1216 }
1217 g->processing_cmdq = false;
1218 }
1219
1220 static void virtio_gpu_process_fenceq(VirtIOGPU *g)
1221 {
1222 struct virtio_gpu_ctrl_command *cmd, *tmp;
1223
1224 QTAILQ_FOREACH_SAFE(cmd, &g->fenceq, next, tmp) {
1225 trace_virtio_gpu_fence_resp(cmd->cmd_hdr.fence_id);
1226 virtio_gpu_ctrl_response_nodata(g, cmd, VIRTIO_GPU_RESP_OK_NODATA);
1227 QTAILQ_REMOVE(&g->fenceq, cmd, next);
1228 g_free(cmd);
1229 g->inflight--;
1230 if (virtio_gpu_stats_enabled(g->parent_obj.conf)) {
1231 trace_virtio_gpu_dec_inflight_fences(g->inflight);
1232 }
1233 }
1234 }
1235
1236 static void virtio_gpu_handle_gl_flushed(VirtIOGPUBase *b)
1237 {
1238 VirtIOGPU *g = container_of(b, VirtIOGPU, parent_obj);
1239
1240 virtio_gpu_process_fenceq(g);
1241 virtio_gpu_process_cmdq(g);
1242 }
1243
1244 static void virtio_gpu_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
1245 {
1246 VirtIOGPU *g = VIRTIO_GPU(vdev);
1247 struct virtio_gpu_ctrl_command *cmd;
1248
1249 if (!virtio_queue_ready(vq)) {
1250 return;
1251 }
1252
1253 cmd = virtqueue_pop(vq, sizeof(struct virtio_gpu_ctrl_command));
1254 while (cmd) {
1255 cmd->vq = vq;
1256 cmd->error = 0;
1257 cmd->finished = false;
1258 QTAILQ_INSERT_TAIL(&g->cmdq, cmd, next);
1259 cmd = virtqueue_pop(vq, sizeof(struct virtio_gpu_ctrl_command));
1260 }
1261
1262 virtio_gpu_process_cmdq(g);
1263 }
1264
1265 static void virtio_gpu_ctrl_bh(void *opaque)
1266 {
1267 VirtIOGPU *g = opaque;
1268 VirtIOGPUClass *vgc = VIRTIO_GPU_GET_CLASS(g);
1269
1270 vgc->handle_ctrl(VIRTIO_DEVICE(g), g->ctrl_vq);
1271 }
1272
1273 static void virtio_gpu_handle_cursor(VirtIODevice *vdev, VirtQueue *vq)
1274 {
1275 VirtIOGPU *g = VIRTIO_GPU(vdev);
1276 VirtQueueElement *elem;
1277 size_t s;
1278 struct virtio_gpu_update_cursor cursor_info;
1279
1280 if (!virtio_queue_ready(vq)) {
1281 return;
1282 }
1283 for (;;) {
1284 elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
1285 if (!elem) {
1286 break;
1287 }
1288
1289 s = iov_to_buf(elem->out_sg, elem->out_num, 0,
1290 &cursor_info, sizeof(cursor_info));
1291 if (s != sizeof(cursor_info)) {
1292 qemu_log_mask(LOG_GUEST_ERROR,
1293 "%s: cursor size incorrect %zu vs %zu\n",
1294 __func__, s, sizeof(cursor_info));
1295 } else {
1296 virtio_gpu_bswap_32(&cursor_info, sizeof(cursor_info));
1297 update_cursor(g, &cursor_info);
1298 }
1299 virtqueue_push(vq, elem, 0);
1300 virtio_notify(vdev, vq);
1301 g_free(elem);
1302 }
1303 }
1304
1305 static void virtio_gpu_cursor_bh(void *opaque)
1306 {
1307 VirtIOGPU *g = opaque;
1308 virtio_gpu_handle_cursor(&g->parent_obj.parent_obj, g->cursor_vq);
1309 }
1310
1311 static bool scanout_vmstate_after_v2(void *opaque, int version)
1312 {
1313 struct VirtIOGPUBase *base = container_of(opaque, VirtIOGPUBase, scanout);
1314 struct VirtIOGPU *gpu = container_of(base, VirtIOGPU, parent_obj);
1315
1316 return gpu->scanout_vmstate_version >= 2;
1317 }
1318
1319 static const VMStateDescription vmstate_virtio_gpu_scanout = {
1320 .name = "virtio-gpu-one-scanout",
1321 .version_id = 1,
1322 .fields = (const VMStateField[]) {
1323 VMSTATE_UINT32(resource_id, struct virtio_gpu_scanout),
1324 VMSTATE_UINT32(width, struct virtio_gpu_scanout),
1325 VMSTATE_UINT32(height, struct virtio_gpu_scanout),
1326 VMSTATE_INT32(x, struct virtio_gpu_scanout),
1327 VMSTATE_INT32(y, struct virtio_gpu_scanout),
1328 VMSTATE_UINT32(cursor.resource_id, struct virtio_gpu_scanout),
1329 VMSTATE_UINT32(cursor.hot_x, struct virtio_gpu_scanout),
1330 VMSTATE_UINT32(cursor.hot_y, struct virtio_gpu_scanout),
1331 VMSTATE_UINT32(cursor.pos.x, struct virtio_gpu_scanout),
1332 VMSTATE_UINT32(cursor.pos.y, struct virtio_gpu_scanout),
1333 VMSTATE_UINT32_TEST(fb.format, struct virtio_gpu_scanout,
1334 scanout_vmstate_after_v2),
1335 VMSTATE_UNUSED_TEST(scanout_vmstate_after_v2, 4),
1336 VMSTATE_UINT32_TEST(fb.width, struct virtio_gpu_scanout,
1337 scanout_vmstate_after_v2),
1338 VMSTATE_UINT32_TEST(fb.height, struct virtio_gpu_scanout,
1339 scanout_vmstate_after_v2),
1340 VMSTATE_UINT32_TEST(fb.stride, struct virtio_gpu_scanout,
1341 scanout_vmstate_after_v2),
1342 VMSTATE_UINT32_TEST(fb.offset, struct virtio_gpu_scanout,
1343 scanout_vmstate_after_v2),
1344 VMSTATE_END_OF_LIST()
1345 },
1346 };
1347
1348 static const VMStateDescription vmstate_virtio_gpu_scanouts = {
1349 .name = "virtio-gpu-scanouts",
1350 .version_id = 1,
1351 .fields = (const VMStateField[]) {
1352 VMSTATE_INT32(parent_obj.enable, struct VirtIOGPU),
1353 VMSTATE_UINT32_EQUAL(parent_obj.conf.max_outputs,
1354 struct VirtIOGPU),
1355 VMSTATE_STRUCT_VARRAY_UINT32(parent_obj.scanout, struct VirtIOGPU,
1356 parent_obj.conf.max_outputs, 1,
1357 vmstate_virtio_gpu_scanout,
1358 struct virtio_gpu_scanout),
1359 VMSTATE_END_OF_LIST()
1360 },
1361 };
1362
1363 static int virtio_gpu_save(QEMUFile *f, void *opaque, size_t size,
1364 const VMStateField *field, JSONWriter *vmdesc)
1365 {
1366 VirtIOGPU *g = opaque;
1367 struct virtio_gpu_simple_resource *res;
1368 Error *err = NULL;
1369 int i, ret;
1370
1371 /* in 2d mode we should never find unprocessed commands here */
1372 assert(QTAILQ_EMPTY(&g->cmdq));
1373
1374 QTAILQ_FOREACH(res, &g->reslist, next) {
1375 if (!res->image) {
1376 continue;
1377 }
1378 qemu_put_be32(f, res->resource_id);
1379 qemu_put_be32(f, res->width);
1380 qemu_put_be32(f, res->height);
1381 qemu_put_be32(f, res->format);
1382 qemu_put_be32(f, res->iov_cnt);
1383 for (i = 0; i < res->iov_cnt; i++) {
1384 qemu_put_be64(f, res->addrs[i]);
1385 qemu_put_be32(f, res->iov[i].iov_len);
1386 }
1387 qemu_put_buffer(f, (void *)pixman_image_get_data(res->image),
1388 pixman_image_get_stride(res->image) * res->height);
1389 }
1390 qemu_put_be32(f, 0); /* end of list */
1391
1392 ret = vmstate_save_state(f, &vmstate_virtio_gpu_scanouts, g, NULL,
1393 &err);
1394 if (ret < 0) {
1395 error_report_err(err);
1396 }
1397 return ret;
1398 }
1399
1400 static bool virtio_gpu_load_restore_mapping(VirtIOGPU *g,
1401 struct virtio_gpu_simple_resource *res)
1402 {
1403 int i;
1404
1405 for (i = 0; i < res->iov_cnt; i++) {
1406 hwaddr len = res->iov[i].iov_len;
1407 res->iov[i].iov_base =
1408 dma_memory_map(VIRTIO_DEVICE(g)->dma_as, res->addrs[i], &len,
1409 DMA_DIRECTION_TO_DEVICE, MEMTXATTRS_UNSPECIFIED);
1410
1411 if (!res->iov[i].iov_base || len != res->iov[i].iov_len) {
1412 /* Clean up the half-a-mapping we just created... */
1413 if (res->iov[i].iov_base) {
1414 dma_memory_unmap(VIRTIO_DEVICE(g)->dma_as, res->iov[i].iov_base,
1415 len, DMA_DIRECTION_TO_DEVICE, 0);
1416 }
1417 /* ...and the mappings for previous loop iterations */
1418 res->iov_cnt = i;
1419 virtio_gpu_cleanup_mapping(g, res);
1420 return false;
1421 }
1422 }
1423
1424 return true;
1425 }
1426
1427 static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size,
1428 const VMStateField *field)
1429 {
1430 VirtIOGPU *g = opaque;
1431 Error *err = NULL;
1432 struct virtio_gpu_simple_resource *res;
1433 uint32_t resource_id, pformat, hostmem, rowstride_bytes;
1434 int i, ret;
1435
1436 g->hostmem = 0;
1437
1438 resource_id = qemu_get_be32(f);
1439 while (resource_id != 0) {
1440 res = virtio_gpu_find_resource(g, resource_id);
1441 if (res) {
1442 return -EINVAL;
1443 }
1444
1445 res = g_new0(struct virtio_gpu_simple_resource, 1);
1446 res->resource_id = resource_id;
1447 res->width = qemu_get_be32(f);
1448 res->height = qemu_get_be32(f);
1449 res->format = qemu_get_be32(f);
1450 res->iov_cnt = qemu_get_be32(f);
1451
1452 /* allocate */
1453 pformat = virtio_gpu_get_pixman_format(res->format);
1454 if (!pformat) {
1455 g_free(res);
1456 return -EINVAL;
1457 }
1458
1459 if (!calc_image_hostmem(pformat, res->width, res->height,
1460 &hostmem, &rowstride_bytes)) {
1461 g_free(res);
1462 return -EINVAL;
1463 }
1464 res->hostmem = hostmem;
1465 if (!qemu_pixman_image_new_shareable(&res->image,
1466 &res->share_handle,
1467 "virtio-gpu res",
1468 pformat,
1469 res->width,
1470 res->height,
1471 rowstride_bytes,
1472 &err)) {
1473 warn_report_err(err);
1474 g_free(res);
1475 return -EINVAL;
1476 }
1477
1478 res->addrs = g_try_new(uint64_t, res->iov_cnt);
1479 res->iov = g_try_new(struct iovec, res->iov_cnt);
1480 if (res->iov_cnt && (!res->addrs || !res->iov)) {
1481 pixman_image_unref(res->image);
1482 g_free(res->addrs);
1483 g_free(res->iov);
1484 g_free(res);
1485 return -EINVAL;
1486 }
1487
1488 /* read data */
1489 for (i = 0; i < res->iov_cnt; i++) {
1490 res->addrs[i] = qemu_get_be64(f);
1491 res->iov[i].iov_len = qemu_get_be32(f);
1492 }
1493 qemu_get_buffer(f, (void *)pixman_image_get_data(res->image),
1494 pixman_image_get_stride(res->image) * res->height);
1495
1496 if (!virtio_gpu_load_restore_mapping(g, res)) {
1497 pixman_image_unref(res->image);
1498 g_free(res);
1499 return -EINVAL;
1500 }
1501
1502 QTAILQ_INSERT_HEAD(&g->reslist, res, next);
1503 g->hostmem += hostmem;
1504 resource_id = qemu_get_be32(f);
1505 }
1506
1507 /* load & apply scanout state */
1508 ret = vmstate_load_state(f, &vmstate_virtio_gpu_scanouts, g, 1, &err);
1509 if (ret < 0) {
1510 error_report_err(err);
1511 }
1512 return ret;
1513 }
1514
1515 static int virtio_gpu_blob_save(QEMUFile *f, void *opaque, size_t size,
1516 const VMStateField *field, JSONWriter *vmdesc)
1517 {
1518 VirtIOGPU *g = opaque;
1519 struct virtio_gpu_simple_resource *res;
1520 int i;
1521
1522 /* in 2d mode we should never find unprocessed commands here */
1523 assert(QTAILQ_EMPTY(&g->cmdq));
1524
1525 QTAILQ_FOREACH(res, &g->reslist, next) {
1526 if (res->image) {
1527 continue;
1528 }
1529 assert(!res->image);
1530 qemu_put_be32(f, res->resource_id);
1531 qemu_put_be32(f, res->blob_size);
1532 qemu_put_be32(f, res->iov_cnt);
1533 for (i = 0; i < res->iov_cnt; i++) {
1534 qemu_put_be64(f, res->addrs[i]);
1535 qemu_put_be32(f, res->iov[i].iov_len);
1536 }
1537 }
1538 qemu_put_be32(f, 0); /* end of list */
1539
1540 return 0;
1541 }
1542
1543 static int virtio_gpu_blob_load(QEMUFile *f, void *opaque, size_t size,
1544 const VMStateField *field)
1545 {
1546 VirtIOGPU *g = opaque;
1547 struct virtio_gpu_simple_resource *res;
1548 uint32_t resource_id;
1549 int i;
1550
1551 resource_id = qemu_get_be32(f);
1552 while (resource_id != 0) {
1553 res = virtio_gpu_find_resource(g, resource_id);
1554 if (res) {
1555 return -EINVAL;
1556 }
1557
1558 res = g_new0(struct virtio_gpu_simple_resource, 1);
1559 res->resource_id = resource_id;
1560 res->blob_size = qemu_get_be32(f);
1561 res->iov_cnt = qemu_get_be32(f);
1562
1563 if (res->iov_cnt) {
1564 res->addrs = g_try_new(uint64_t, res->iov_cnt);
1565 res->iov = g_try_new(struct iovec, res->iov_cnt);
1566 if (!res->addrs || !res->iov) {
1567 g_free(res->addrs);
1568 g_free(res->iov);
1569 g_free(res);
1570 return -EINVAL;
1571 }
1572
1573 /* read data */
1574 for (i = 0; i < res->iov_cnt; i++) {
1575 res->addrs[i] = qemu_get_be64(f);
1576 res->iov[i].iov_len = qemu_get_be32(f);
1577 }
1578
1579 if (iov_size(res->iov, res->iov_cnt) < res->blob_size) {
1580 g_free(res->addrs);
1581 g_free(res->iov);
1582 g_free(res);
1583 return -EINVAL;
1584 }
1585
1586 if (!virtio_gpu_load_restore_mapping(g, res)) {
1587 g_free(res);
1588 return -EINVAL;
1589 }
1590
1591 if (!virtio_gpu_init_udmabuf(res)) {
1592 virtio_gpu_cleanup_mapping(g, res);
1593 g_free(res);
1594 return -EINVAL;
1595 }
1596 }
1597
1598 QTAILQ_INSERT_HEAD(&g->reslist, res, next);
1599 resource_id = qemu_get_be32(f);
1600 }
1601
1602 return 0;
1603 }
1604
1605 static int virtio_gpu_post_load(void *opaque, int version_id)
1606 {
1607 VirtIOGPU *g = opaque;
1608 struct virtio_gpu_scanout *scanout;
1609 struct virtio_gpu_simple_resource *res;
1610 int i;
1611
1612 for (i = 0; i < g->parent_obj.conf.max_outputs; i++) {
1613 scanout = &g->parent_obj.scanout[i];
1614 if (!scanout->resource_id) {
1615 continue;
1616 }
1617
1618 res = virtio_gpu_find_resource(g, scanout->resource_id);
1619 if (!res) {
1620 return -EINVAL;
1621 }
1622
1623 if (scanout->fb.format != 0) {
1624 uint32_t error = 0;
1625 struct virtio_gpu_rect r = {
1626 .x = scanout->x,
1627 .y = scanout->y,
1628 .width = scanout->width,
1629 .height = scanout->height
1630 };
1631
1632 if (!virtio_gpu_do_set_scanout(g, i, &scanout->fb, res, &r, &error)) {
1633 return -EINVAL;
1634 }
1635 } else {
1636 /* legacy v1 migration support */
1637 if (!res->image) {
1638 return -EINVAL;
1639 }
1640 scanout->ds = qemu_create_displaysurface_pixman(res->image);
1641 qemu_displaysurface_set_share_handle(scanout->ds, res->share_handle, 0);
1642 qemu_console_set_surface(scanout->con, scanout->ds);
1643 }
1644
1645 qemu_console_update_full(scanout->con);
1646 if (scanout->cursor.resource_id) {
1647 update_cursor(g, &scanout->cursor);
1648 }
1649 res->scanout_bitmask |= (1 << i);
1650 }
1651
1652 return 0;
1653 }
1654
1655 void virtio_gpu_device_realize(DeviceState *qdev, Error **errp)
1656 {
1657 VirtIODevice *vdev = VIRTIO_DEVICE(qdev);
1658 VirtIOGPU *g = VIRTIO_GPU(qdev);
1659
1660 if (virtio_gpu_blob_enabled(g->parent_obj.conf)) {
1661 if (!virtio_gpu_rutabaga_enabled(g->parent_obj.conf) &&
1662 !virtio_gpu_virgl_enabled(g->parent_obj.conf) &&
1663 !virtio_gpu_have_udmabuf()) {
1664 error_setg(errp, "need rutabaga or udmabuf for blob resources");
1665 return;
1666 }
1667
1668 #ifdef VIRGL_VERSION_MAJOR
1669 #if VIRGL_VERSION_MAJOR < 1
1670 if (virtio_gpu_virgl_enabled(g->parent_obj.conf)) {
1671 error_setg(errp, "old virglrenderer, blob resources unsupported");
1672 return;
1673 }
1674 #endif
1675 #endif
1676 }
1677
1678 if (virtio_gpu_venus_enabled(g->parent_obj.conf)) {
1679 #ifdef VIRGL_VERSION_MAJOR
1680 #if VIRGL_VERSION_MAJOR >= 1
1681 if (!virtio_gpu_blob_enabled(g->parent_obj.conf) ||
1682 !virtio_gpu_hostmem_enabled(g->parent_obj.conf)) {
1683 error_setg(errp, "venus requires enabled blob and hostmem options");
1684 return;
1685 }
1686 #else
1687 error_setg(errp, "old virglrenderer, venus unsupported");
1688 return;
1689 #endif
1690 #endif
1691 }
1692
1693 if (virtio_gpu_drm_enabled(g->parent_obj.conf)) {
1694 #ifdef VIRGL_VERSION_MAJOR
1695 #if VIRGL_VERSION_MAJOR >= 1
1696 if (!virtio_gpu_blob_enabled(g->parent_obj.conf) ||
1697 !virtio_gpu_hostmem_enabled(g->parent_obj.conf)) {
1698 error_setg(errp, "drm requires enabled blob and hostmem options");
1699 return;
1700 }
1701 #else
1702 error_setg(errp, "old virglrenderer, drm unsupported");
1703 return;
1704 #endif
1705 #endif
1706 }
1707
1708 if (!virtio_gpu_base_device_realize(qdev,
1709 virtio_gpu_handle_ctrl_cb,
1710 virtio_gpu_handle_cursor_cb,
1711 errp)) {
1712 return;
1713 }
1714
1715 g->ctrl_vq = virtio_get_queue(vdev, 0);
1716 g->cursor_vq = virtio_get_queue(vdev, 1);
1717 g->ctrl_bh = virtio_bh_io_new_guarded(qdev, virtio_gpu_ctrl_bh, g);
1718 g->cursor_bh = virtio_bh_io_new_guarded(qdev, virtio_gpu_cursor_bh, g);
1719 g->reset_bh = virtio_bh_io_new_guarded(qdev, virtio_gpu_reset_bh, g);
1720 qemu_cond_init(&g->reset_cond);
1721 QTAILQ_INIT(&g->reslist);
1722 QTAILQ_INIT(&g->cmdq);
1723 QTAILQ_INIT(&g->fenceq);
1724 }
1725
1726 static void virtio_gpu_device_unrealize(DeviceState *qdev)
1727 {
1728 VirtIOGPU *g = VIRTIO_GPU(qdev);
1729
1730 g_clear_pointer(&g->ctrl_bh, qemu_bh_delete);
1731 g_clear_pointer(&g->cursor_bh, qemu_bh_delete);
1732 g_clear_pointer(&g->reset_bh, qemu_bh_delete);
1733 qemu_cond_destroy(&g->reset_cond);
1734 virtio_gpu_base_device_unrealize(qdev);
1735 }
1736
1737 static void virtio_gpu_reset_bh(void *opaque)
1738 {
1739 VirtIOGPU *g = VIRTIO_GPU(opaque);
1740 VirtIOGPUClass *vgc = VIRTIO_GPU_GET_CLASS(g);
1741 struct virtio_gpu_simple_resource *res, *tmp;
1742 uint32_t resource_id;
1743 Error *local_err = NULL;
1744 int i = 0;
1745
1746 QTAILQ_FOREACH_SAFE(res, &g->reslist, next, tmp) {
1747 resource_id = res->resource_id;
1748 vgc->resource_destroy(g, res, &local_err);
1749 if (local_err) {
1750 error_append_hint(&local_err, "%s: %s resource_destroy"
1751 "for resource_id = %"PRIu32" failed.\n",
1752 __func__, object_get_typename(OBJECT(g)),
1753 resource_id);
1754 /* error_report_err frees the error object for us */
1755 error_report_err(local_err);
1756 local_err = NULL;
1757 }
1758 }
1759
1760 for (i = 0; i < g->parent_obj.conf.max_outputs; i++) {
1761 qemu_console_set_surface(g->parent_obj.scanout[i].con, NULL);
1762 }
1763
1764 g->reset_finished = true;
1765 qemu_cond_signal(&g->reset_cond);
1766 }
1767
1768 void virtio_gpu_reset(VirtIODevice *vdev)
1769 {
1770 VirtIOGPU *g = VIRTIO_GPU(vdev);
1771 struct virtio_gpu_ctrl_command *cmd;
1772
1773 if (qemu_in_vcpu_thread()) {
1774 g->reset_finished = false;
1775 qemu_bh_schedule(g->reset_bh);
1776 while (!g->reset_finished) {
1777 qemu_cond_wait_bql(&g->reset_cond);
1778 }
1779 } else {
1780 aio_bh_call(g->reset_bh);
1781 }
1782
1783 while (!QTAILQ_EMPTY(&g->cmdq)) {
1784 cmd = QTAILQ_FIRST(&g->cmdq);
1785 QTAILQ_REMOVE(&g->cmdq, cmd, next);
1786 virtqueue_detach_element(cmd->vq, &cmd->elem, 0);
1787 g_free(cmd);
1788 }
1789
1790 while (!QTAILQ_EMPTY(&g->fenceq)) {
1791 cmd = QTAILQ_FIRST(&g->fenceq);
1792 QTAILQ_REMOVE(&g->fenceq, cmd, next);
1793 virtqueue_detach_element(cmd->vq, &cmd->elem, 0);
1794 g->inflight--;
1795 g_free(cmd);
1796 }
1797
1798 virtio_gpu_base_reset(VIRTIO_GPU_BASE(vdev));
1799 }
1800
1801 static void
1802 virtio_gpu_get_config(VirtIODevice *vdev, uint8_t *config)
1803 {
1804 VirtIOGPUBase *g = VIRTIO_GPU_BASE(vdev);
1805
1806 memcpy(config, &g->virtio_config, sizeof(g->virtio_config));
1807 }
1808
1809 static void
1810 virtio_gpu_set_config(VirtIODevice *vdev, const uint8_t *config)
1811 {
1812 VirtIOGPUBase *g = VIRTIO_GPU_BASE(vdev);
1813 const struct virtio_gpu_config *vgconfig =
1814 (const struct virtio_gpu_config *)config;
1815
1816 if (vgconfig->events_clear) {
1817 g->virtio_config.events_read &= ~vgconfig->events_clear;
1818 }
1819 }
1820
1821 static bool virtio_gpu_blob_state_needed(void *opaque)
1822 {
1823 VirtIOGPU *g = VIRTIO_GPU(opaque);
1824
1825 return virtio_gpu_blob_enabled(g->parent_obj.conf);
1826 }
1827
1828 const VMStateDescription vmstate_virtio_gpu_blob_state = {
1829 .name = "virtio-gpu/blob",
1830 .minimum_version_id = VIRTIO_GPU_VM_VERSION,
1831 .version_id = VIRTIO_GPU_VM_VERSION,
1832 .needed = virtio_gpu_blob_state_needed,
1833 .fields = (const VMStateField[]){
1834 {
1835 .name = "virtio-gpu/blob",
1836 .info = &(const VMStateInfo) {
1837 .name = "blob",
1838 .get = virtio_gpu_blob_load,
1839 .put = virtio_gpu_blob_save,
1840 },
1841 .flags = VMS_SINGLE,
1842 } /* device */,
1843 VMSTATE_END_OF_LIST()
1844 },
1845 };
1846
1847 /*
1848 * For historical reasons virtio_gpu does not adhere to virtio migration
1849 * scheme as described in doc/virtio-migration.txt, in a sense that no
1850 * save/load callback are provided to the core. Instead the device data
1851 * is saved/loaded after the core data.
1852 *
1853 * Because of this we need a special vmsd.
1854 */
1855 static const VMStateDescription vmstate_virtio_gpu = {
1856 .name = "virtio-gpu",
1857 .minimum_version_id = VIRTIO_GPU_VM_VERSION,
1858 .version_id = VIRTIO_GPU_VM_VERSION,
1859 .fields = (const VMStateField[]) {
1860 VMSTATE_VIRTIO_DEVICE /* core */,
1861 {
1862 .name = "virtio-gpu",
1863 .info = &(const VMStateInfo) {
1864 .name = "virtio-gpu",
1865 .get = virtio_gpu_load,
1866 .put = virtio_gpu_save,
1867 },
1868 .flags = VMS_SINGLE,
1869 } /* device */,
1870 VMSTATE_END_OF_LIST()
1871 },
1872 .subsections = (const VMStateDescription * const []) {
1873 &vmstate_virtio_gpu_blob_state,
1874 NULL
1875 },
1876 .post_load = virtio_gpu_post_load,
1877 };
1878
1879 static const Property virtio_gpu_properties[] = {
1880 VIRTIO_GPU_BASE_PROPERTIES(VirtIOGPU, parent_obj.conf),
1881 DEFINE_PROP_SIZE("max_hostmem", VirtIOGPU, conf_max_hostmem,
1882 256 * MiB),
1883 DEFINE_PROP_BIT("blob", VirtIOGPU, parent_obj.conf.flags,
1884 VIRTIO_GPU_FLAG_BLOB_ENABLED, false),
1885 DEFINE_PROP_SIZE("hostmem", VirtIOGPU, parent_obj.conf.hostmem, 0),
1886 DEFINE_PROP_UINT8("x-scanout-vmstate-version", VirtIOGPU, scanout_vmstate_version, 2),
1887 };
1888
1889 static void virtio_gpu_class_init(ObjectClass *klass, const void *data)
1890 {
1891 DeviceClass *dc = DEVICE_CLASS(klass);
1892 VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
1893 VirtIOGPUClass *vgc = VIRTIO_GPU_CLASS(klass);
1894 VirtIOGPUBaseClass *vgbc = &vgc->parent;
1895
1896 vgc->handle_ctrl = virtio_gpu_handle_ctrl;
1897 vgc->process_cmd = virtio_gpu_simple_process_cmd;
1898 vgc->update_cursor_data = virtio_gpu_update_cursor_data;
1899 vgc->resource_destroy = virtio_gpu_resource_destroy;
1900 vgbc->gl_flushed = virtio_gpu_handle_gl_flushed;
1901
1902 vdc->realize = virtio_gpu_device_realize;
1903 vdc->unrealize = virtio_gpu_device_unrealize;
1904 vdc->reset = virtio_gpu_reset;
1905 vdc->get_config = virtio_gpu_get_config;
1906 vdc->set_config = virtio_gpu_set_config;
1907
1908 dc->vmsd = &vmstate_virtio_gpu;
1909 device_class_set_props(dc, virtio_gpu_properties);
1910 }
1911
1912 static const TypeInfo virtio_gpu_info = {
1913 .name = TYPE_VIRTIO_GPU,
1914 .parent = TYPE_VIRTIO_GPU_BASE,
1915 .instance_size = sizeof(VirtIOGPU),
1916 .class_size = sizeof(VirtIOGPUClass),
1917 .class_init = virtio_gpu_class_init,
1918 };
1919 module_obj(TYPE_VIRTIO_GPU);
1920 module_kconfig(VIRTIO_GPU);
1921
1922 static void virtio_register_types(void)
1923 {
1924 type_register_static(&virtio_gpu_info);
1925 }
1926
1927 type_init(virtio_register_types)