master
c 1,180 lines 36 KB
Raw
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2
3 #include "qemu/osdep.h"
4 #include "qapi/error.h"
5 #include "qemu/error-report.h"
6 #include "qemu/iov.h"
7 #include "trace.h"
8 #include "hw/virtio/virtio.h"
9 #include "hw/virtio/virtio-gpu.h"
10 #include "hw/virtio/virtio-gpu-pixman.h"
11 #include "hw/virtio/virtio-iommu.h"
12 #include "migration/blocker.h"
13
14 #include <glib/gmem.h>
15 #include <rutabaga_gfx/rutabaga_gfx_ffi.h>
16
17 #define CHECK(condition, cmd) \
18 do { \
19 if (!(condition)) { \
20 error_report("CHECK failed in %s() %s:" "%d", __func__, \
21 __FILE__, __LINE__); \
22 (cmd)->error = VIRTIO_GPU_RESP_ERR_UNSPEC; \
23 return; \
24 } \
25 } while (0)
26
27 struct rutabaga_aio_data {
28 struct VirtIOGPURutabaga *vr;
29 struct rutabaga_fence fence;
30 };
31
32 static void
33 virtio_gpu_rutabaga_update_cursor(VirtIOGPU *g, struct virtio_gpu_scanout *s,
34 uint32_t resource_id)
35 {
36 struct virtio_gpu_simple_resource *res;
37 struct rutabaga_transfer transfer = { 0 };
38 struct iovec transfer_iovec;
39
40 VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
41
42 res = virtio_gpu_find_resource(g, resource_id);
43 if (!res) {
44 return;
45 }
46
47 if (res->width != s->current_cursor->width ||
48 res->height != s->current_cursor->height) {
49 return;
50 }
51
52 transfer.x = 0;
53 transfer.y = 0;
54 transfer.z = 0;
55 transfer.w = res->width;
56 transfer.h = res->height;
57 transfer.d = 1;
58
59 transfer_iovec.iov_base = s->current_cursor->data;
60 transfer_iovec.iov_len = res->width * res->height * 4;
61
62 rutabaga_resource_transfer_read(vr->rutabaga, 0,
63 resource_id, &transfer,
64 &transfer_iovec);
65 }
66
67 static void
68 virtio_gpu_rutabaga_gl_flushed(VirtIOGPUBase *b)
69 {
70 VirtIOGPU *g = VIRTIO_GPU(b);
71 virtio_gpu_process_cmdq(g);
72 }
73
74 static void
75 rutabaga_cmd_create_resource_2d(VirtIOGPU *g,
76 struct virtio_gpu_ctrl_command *cmd)
77 {
78 int32_t result;
79 struct rutabaga_create_3d rc_3d = { 0 };
80 struct virtio_gpu_simple_resource *res;
81 struct virtio_gpu_resource_create_2d c2d;
82
83 VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
84
85 VIRTIO_GPU_FILL_CMD(c2d);
86 trace_virtio_gpu_cmd_res_create_2d(c2d.resource_id, c2d.format,
87 c2d.width, c2d.height);
88
89 rc_3d.target = 2;
90 rc_3d.format = c2d.format;
91 rc_3d.bind = (1 << 1);
92 rc_3d.width = c2d.width;
93 rc_3d.height = c2d.height;
94 rc_3d.depth = 1;
95 rc_3d.array_size = 1;
96 rc_3d.last_level = 0;
97 rc_3d.nr_samples = 0;
98 rc_3d.flags = VIRTIO_GPU_RESOURCE_FLAG_Y_0_TOP;
99
100 result = rutabaga_resource_create_3d(vr->rutabaga, c2d.resource_id, &rc_3d);
101 CHECK(!result, cmd);
102
103 res = g_new0(struct virtio_gpu_simple_resource, 1);
104 res->width = c2d.width;
105 res->height = c2d.height;
106 res->format = c2d.format;
107 res->resource_id = c2d.resource_id;
108
109 QTAILQ_INSERT_HEAD(&g->reslist, res, next);
110 }
111
112 static void
113 rutabaga_cmd_create_resource_3d(VirtIOGPU *g,
114 struct virtio_gpu_ctrl_command *cmd)
115 {
116 int32_t result;
117 struct rutabaga_create_3d rc_3d = { 0 };
118 struct virtio_gpu_simple_resource *res;
119 struct virtio_gpu_resource_create_3d c3d;
120
121 VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
122
123 VIRTIO_GPU_FILL_CMD(c3d);
124
125 trace_virtio_gpu_cmd_res_create_3d(c3d.resource_id, c3d.format,
126 c3d.width, c3d.height, c3d.depth);
127
128 rc_3d.target = c3d.target;
129 rc_3d.format = c3d.format;
130 rc_3d.bind = c3d.bind;
131 rc_3d.width = c3d.width;
132 rc_3d.height = c3d.height;
133 rc_3d.depth = c3d.depth;
134 rc_3d.array_size = c3d.array_size;
135 rc_3d.last_level = c3d.last_level;
136 rc_3d.nr_samples = c3d.nr_samples;
137 rc_3d.flags = c3d.flags;
138
139 result = rutabaga_resource_create_3d(vr->rutabaga, c3d.resource_id, &rc_3d);
140 CHECK(!result, cmd);
141
142 res = g_new0(struct virtio_gpu_simple_resource, 1);
143 res->width = c3d.width;
144 res->height = c3d.height;
145 res->format = c3d.format;
146 res->resource_id = c3d.resource_id;
147
148 QTAILQ_INSERT_HEAD(&g->reslist, res, next);
149 }
150
151 static void
152 virtio_gpu_rutabaga_resource_unref(VirtIOGPU *g,
153 struct virtio_gpu_simple_resource *res,
154 Error **errp)
155 {
156 int32_t result;
157 VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
158
159 result = rutabaga_resource_unref(vr->rutabaga, res->resource_id);
160 if (result) {
161 error_setg_errno(errp,
162 (int)result,
163 "%s: rutabaga_resource_unref returned %"PRIi32
164 " for resource_id = %"PRIu32, __func__, result,
165 res->resource_id);
166 }
167
168 if (res->image) {
169 pixman_image_unref(res->image);
170 }
171
172 QTAILQ_REMOVE(&g->reslist, res, next);
173 g_free(res);
174 }
175
176 static void
177 rutabaga_cmd_resource_unref(VirtIOGPU *g,
178 struct virtio_gpu_ctrl_command *cmd)
179 {
180 int32_t result = 0;
181 struct virtio_gpu_simple_resource *res;
182 struct virtio_gpu_resource_unref unref;
183 Error *local_err = NULL;
184
185 VIRTIO_GPU_FILL_CMD(unref);
186
187 trace_virtio_gpu_cmd_res_unref(unref.resource_id);
188
189 res = virtio_gpu_find_resource(g, unref.resource_id);
190 CHECK(res, cmd);
191
192 virtio_gpu_rutabaga_resource_unref(g, res, &local_err);
193 if (local_err) {
194 error_report_err(local_err);
195 /* local_err was freed, do not reuse it. */
196 local_err = NULL;
197 result = 1;
198 }
199 CHECK(!result, cmd);
200 }
201
202 static void
203 rutabaga_cmd_context_create(VirtIOGPU *g,
204 struct virtio_gpu_ctrl_command *cmd)
205 {
206 int32_t result;
207 struct virtio_gpu_ctx_create cc;
208
209 VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
210
211 VIRTIO_GPU_FILL_CMD(cc);
212 trace_virtio_gpu_cmd_ctx_create(cc.hdr.ctx_id,
213 cc.debug_name);
214
215 result = rutabaga_context_create(vr->rutabaga, cc.hdr.ctx_id,
216 cc.context_init, cc.debug_name, cc.nlen);
217 CHECK(!result, cmd);
218 }
219
220 static void
221 rutabaga_cmd_context_destroy(VirtIOGPU *g,
222 struct virtio_gpu_ctrl_command *cmd)
223 {
224 int32_t result;
225 struct virtio_gpu_ctx_destroy cd;
226
227 VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
228
229 VIRTIO_GPU_FILL_CMD(cd);
230 trace_virtio_gpu_cmd_ctx_destroy(cd.hdr.ctx_id);
231
232 result = rutabaga_context_destroy(vr->rutabaga, cd.hdr.ctx_id);
233 CHECK(!result, cmd);
234 }
235
236 static void
237 rutabaga_cmd_resource_flush(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd)
238 {
239 int32_t result, i;
240 struct virtio_gpu_scanout *scanout = NULL;
241 struct virtio_gpu_simple_resource *res;
242 struct rutabaga_transfer transfer = { 0 };
243 struct iovec transfer_iovec;
244 struct virtio_gpu_resource_flush rf;
245 bool found = false;
246
247 VirtIOGPUBase *vb = VIRTIO_GPU_BASE(g);
248 VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
249 if (vr->headless) {
250 return;
251 }
252
253 VIRTIO_GPU_FILL_CMD(rf);
254 trace_virtio_gpu_cmd_res_flush(rf.resource_id,
255 rf.r.width, rf.r.height, rf.r.x, rf.r.y);
256
257 res = virtio_gpu_find_resource(g, rf.resource_id);
258 CHECK(res, cmd);
259
260 for (i = 0; i < vb->conf.max_outputs; i++) {
261 scanout = &vb->scanout[i];
262 if (i == res->scanout_bitmask) {
263 found = true;
264 break;
265 }
266 }
267
268 if (!found) {
269 return;
270 }
271
272 transfer.x = 0;
273 transfer.y = 0;
274 transfer.z = 0;
275 transfer.w = res->width;
276 transfer.h = res->height;
277 transfer.d = 1;
278
279 transfer_iovec.iov_base = pixman_image_get_data(res->image);
280 transfer_iovec.iov_len = res->width * res->height * 4;
281
282 result = rutabaga_resource_transfer_read(vr->rutabaga, 0,
283 rf.resource_id, &transfer,
284 &transfer_iovec);
285 CHECK(!result, cmd);
286 qemu_console_update_full(scanout->con);
287 }
288
289 static void
290 rutabaga_cmd_set_scanout(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd)
291 {
292 struct virtio_gpu_simple_resource *res;
293 struct virtio_gpu_scanout *scanout = NULL;
294 struct virtio_gpu_set_scanout ss;
295
296 VirtIOGPUBase *vb = VIRTIO_GPU_BASE(g);
297 VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
298 if (vr->headless) {
299 return;
300 }
301
302 VIRTIO_GPU_FILL_CMD(ss);
303 trace_virtio_gpu_cmd_set_scanout(ss.scanout_id, ss.resource_id,
304 ss.r.width, ss.r.height, ss.r.x, ss.r.y);
305
306 CHECK(ss.scanout_id < vb->conf.max_outputs, cmd);
307 scanout = &vb->scanout[ss.scanout_id];
308
309 if (ss.resource_id == 0) {
310 qemu_console_set_surface(scanout->con, NULL);
311 qemu_console_gl_scanout_disable(scanout->con);
312 return;
313 }
314
315 res = virtio_gpu_find_resource(g, ss.resource_id);
316 CHECK(res, cmd);
317
318 if (!virtio_gpu_check_scanout_bounds(ss.scanout_id, ss.resource_id,
319 res->width, res->height, &ss.r,
320 &cmd->error)) {
321 return;
322 }
323
324 if (!res->image) {
325 pixman_format_code_t pformat;
326 pformat = virtio_gpu_get_pixman_format(res->format);
327 CHECK(pformat, cmd);
328
329 res->image = pixman_image_create_bits(pformat,
330 res->width,
331 res->height,
332 NULL, 0);
333 CHECK(res->image, cmd);
334 pixman_image_ref(res->image);
335 }
336
337 vb->enable = 1;
338
339 /* realloc the surface ptr */
340 scanout->ds = qemu_create_displaysurface_pixman(res->image);
341 qemu_console_set_surface(scanout->con, NULL);
342 qemu_console_set_surface(scanout->con, scanout->ds);
343 res->scanout_bitmask = ss.scanout_id;
344 }
345
346 static void
347 rutabaga_cmd_submit_3d(VirtIOGPU *g,
348 struct virtio_gpu_ctrl_command *cmd)
349 {
350 int32_t result;
351 struct virtio_gpu_cmd_submit cs;
352 struct rutabaga_command rutabaga_cmd = { 0 };
353 g_autofree uint8_t *buf = NULL;
354 size_t s;
355
356 VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
357
358 VIRTIO_GPU_FILL_CMD(cs);
359 trace_virtio_gpu_cmd_ctx_submit(cs.hdr.ctx_id, cs.size);
360
361 if (cs.size > VIRTIO_GPU_MAX_CMD_SUBMIT_SIZE) {
362 qemu_log_mask(LOG_GUEST_ERROR,
363 "%s: command buffer too large (%u)\n",
364 __func__, cs.size);
365 cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
366 return;
367 }
368
369 buf = g_try_new0(uint8_t, cs.size);
370 if (!buf && cs.size) {
371 cmd->error = VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY;
372 return;
373 }
374 s = iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num,
375 sizeof(cs), buf, cs.size);
376 if (s != cs.size) {
377 qemu_log_mask(LOG_GUEST_ERROR,
378 "%s: size mismatch (%zu/%u)\n",
379 __func__, s, cs.size);
380 cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
381 return;
382 }
383
384 rutabaga_cmd.ctx_id = cs.hdr.ctx_id;
385 rutabaga_cmd.cmd = buf;
386 rutabaga_cmd.cmd_size = cs.size;
387
388 result = rutabaga_submit_command(vr->rutabaga, &rutabaga_cmd);
389 CHECK(!result, cmd);
390 }
391
392 static void
393 rutabaga_cmd_transfer_to_host_2d(VirtIOGPU *g,
394 struct virtio_gpu_ctrl_command *cmd)
395 {
396 int32_t result;
397 struct rutabaga_transfer transfer = { 0 };
398 struct virtio_gpu_transfer_to_host_2d t2d;
399
400 VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
401
402 VIRTIO_GPU_FILL_CMD(t2d);
403 trace_virtio_gpu_cmd_res_xfer_toh_2d(t2d.resource_id);
404
405 transfer.x = t2d.r.x;
406 transfer.y = t2d.r.y;
407 transfer.z = 0;
408 transfer.w = t2d.r.width;
409 transfer.h = t2d.r.height;
410 transfer.d = 1;
411
412 result = rutabaga_resource_transfer_write(vr->rutabaga, 0, t2d.resource_id,
413 &transfer);
414 CHECK(!result, cmd);
415 }
416
417 static void
418 rutabaga_cmd_transfer_to_host_3d(VirtIOGPU *g,
419 struct virtio_gpu_ctrl_command *cmd)
420 {
421 int32_t result;
422 struct rutabaga_transfer transfer = { 0 };
423 struct virtio_gpu_transfer_host_3d t3d;
424
425 VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
426
427 VIRTIO_GPU_FILL_CMD(t3d);
428 trace_virtio_gpu_cmd_res_xfer_toh_3d(t3d.resource_id);
429
430 transfer.x = t3d.box.x;
431 transfer.y = t3d.box.y;
432 transfer.z = t3d.box.z;
433 transfer.w = t3d.box.w;
434 transfer.h = t3d.box.h;
435 transfer.d = t3d.box.d;
436 transfer.level = t3d.level;
437 transfer.stride = t3d.stride;
438 transfer.layer_stride = t3d.layer_stride;
439 transfer.offset = t3d.offset;
440
441 result = rutabaga_resource_transfer_write(vr->rutabaga, t3d.hdr.ctx_id,
442 t3d.resource_id, &transfer);
443 CHECK(!result, cmd);
444 }
445
446 static void
447 rutabaga_cmd_transfer_from_host_3d(VirtIOGPU *g,
448 struct virtio_gpu_ctrl_command *cmd)
449 {
450 int32_t result;
451 struct rutabaga_transfer transfer = { 0 };
452 struct virtio_gpu_transfer_host_3d t3d;
453
454 VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
455
456 VIRTIO_GPU_FILL_CMD(t3d);
457 trace_virtio_gpu_cmd_res_xfer_fromh_3d(t3d.resource_id);
458
459 transfer.x = t3d.box.x;
460 transfer.y = t3d.box.y;
461 transfer.z = t3d.box.z;
462 transfer.w = t3d.box.w;
463 transfer.h = t3d.box.h;
464 transfer.d = t3d.box.d;
465 transfer.level = t3d.level;
466 transfer.stride = t3d.stride;
467 transfer.layer_stride = t3d.layer_stride;
468 transfer.offset = t3d.offset;
469
470 result = rutabaga_resource_transfer_read(vr->rutabaga, t3d.hdr.ctx_id,
471 t3d.resource_id, &transfer, NULL);
472 CHECK(!result, cmd);
473 }
474
475 static void
476 rutabaga_cmd_attach_backing(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd)
477 {
478 struct rutabaga_iovecs vecs = { 0 };
479 struct virtio_gpu_simple_resource *res;
480 struct virtio_gpu_resource_attach_backing att_rb;
481 int ret;
482
483 VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
484
485 VIRTIO_GPU_FILL_CMD(att_rb);
486 trace_virtio_gpu_cmd_res_back_attach(att_rb.resource_id);
487
488 res = virtio_gpu_find_resource(g, att_rb.resource_id);
489 CHECK(res, cmd);
490 CHECK(!res->iov, cmd);
491
492 ret = virtio_gpu_create_mapping_iov(g, att_rb.nr_entries, sizeof(att_rb),
493 cmd, NULL, &res->iov, &res->iov_cnt);
494 CHECK(!ret, cmd);
495
496 vecs.iovecs = res->iov;
497 vecs.num_iovecs = res->iov_cnt;
498
499 ret = rutabaga_resource_attach_backing(vr->rutabaga, att_rb.resource_id,
500 &vecs);
501 if (ret != 0) {
502 virtio_gpu_cleanup_mapping(g, res);
503 }
504
505 CHECK(!ret, cmd);
506 }
507
508 static void
509 rutabaga_cmd_detach_backing(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd)
510 {
511 struct virtio_gpu_simple_resource *res;
512 struct virtio_gpu_resource_detach_backing detach_rb;
513
514 VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
515
516 VIRTIO_GPU_FILL_CMD(detach_rb);
517 trace_virtio_gpu_cmd_res_back_detach(detach_rb.resource_id);
518
519 res = virtio_gpu_find_resource(g, detach_rb.resource_id);
520 CHECK(res, cmd);
521
522 rutabaga_resource_detach_backing(vr->rutabaga,
523 detach_rb.resource_id);
524
525 virtio_gpu_cleanup_mapping(g, res);
526 }
527
528 static void
529 rutabaga_cmd_ctx_attach_resource(VirtIOGPU *g,
530 struct virtio_gpu_ctrl_command *cmd)
531 {
532 int32_t result;
533 struct virtio_gpu_ctx_resource att_res;
534
535 VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
536
537 VIRTIO_GPU_FILL_CMD(att_res);
538 trace_virtio_gpu_cmd_ctx_res_attach(att_res.hdr.ctx_id,
539 att_res.resource_id);
540
541 result = rutabaga_context_attach_resource(vr->rutabaga, att_res.hdr.ctx_id,
542 att_res.resource_id);
543 CHECK(!result, cmd);
544 }
545
546 static void
547 rutabaga_cmd_ctx_detach_resource(VirtIOGPU *g,
548 struct virtio_gpu_ctrl_command *cmd)
549 {
550 int32_t result;
551 struct virtio_gpu_ctx_resource det_res;
552
553 VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
554
555 VIRTIO_GPU_FILL_CMD(det_res);
556 trace_virtio_gpu_cmd_ctx_res_detach(det_res.hdr.ctx_id,
557 det_res.resource_id);
558
559 result = rutabaga_context_detach_resource(vr->rutabaga, det_res.hdr.ctx_id,
560 det_res.resource_id);
561 CHECK(!result, cmd);
562 }
563
564 static void
565 rutabaga_cmd_get_capset_info(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd)
566 {
567 int32_t result;
568 struct virtio_gpu_get_capset_info info;
569 struct virtio_gpu_resp_capset_info resp;
570
571 VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
572
573 VIRTIO_GPU_FILL_CMD(info);
574
575 memset(&resp, 0, sizeof(resp));
576
577 result = rutabaga_get_capset_info(vr->rutabaga, info.capset_index,
578 &resp.capset_id, &resp.capset_max_version,
579 &resp.capset_max_size);
580 CHECK(!result, cmd);
581
582 resp.hdr.type = VIRTIO_GPU_RESP_OK_CAPSET_INFO;
583 virtio_gpu_ctrl_response(g, cmd, &resp.hdr, sizeof(resp));
584 }
585
586 static void
587 rutabaga_cmd_get_capset(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd)
588 {
589 int32_t result;
590 struct virtio_gpu_get_capset gc;
591 struct virtio_gpu_resp_capset *resp;
592 uint32_t capset_size, capset_version;
593 uint32_t current_id, i;
594
595 VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
596
597 VIRTIO_GPU_FILL_CMD(gc);
598 for (i = 0; i < vr->num_capsets; i++) {
599 result = rutabaga_get_capset_info(vr->rutabaga, i,
600 &current_id, &capset_version,
601 &capset_size);
602 CHECK(!result, cmd);
603
604 if (current_id == gc.capset_id) {
605 break;
606 }
607 }
608
609 CHECK(i < vr->num_capsets, cmd);
610
611 resp = g_malloc0(sizeof(*resp) + capset_size);
612 resp->hdr.type = VIRTIO_GPU_RESP_OK_CAPSET;
613 rutabaga_get_capset(vr->rutabaga, gc.capset_id, gc.capset_version,
614 resp->capset_data, capset_size);
615
616 virtio_gpu_ctrl_response(g, cmd, &resp->hdr, sizeof(*resp) + capset_size);
617 g_free(resp);
618 }
619
620 static void
621 rutabaga_cmd_resource_create_blob(VirtIOGPU *g,
622 struct virtio_gpu_ctrl_command *cmd)
623 {
624 int result;
625 struct rutabaga_iovecs vecs = { 0 };
626 g_autofree struct virtio_gpu_simple_resource *res = NULL;
627 struct virtio_gpu_resource_create_blob cblob;
628 struct rutabaga_create_blob rc_blob = { 0 };
629
630 VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
631
632 VIRTIO_GPU_FILL_CMD(cblob);
633 trace_virtio_gpu_cmd_res_create_blob(cblob.resource_id, cblob.size);
634
635 CHECK(cblob.resource_id != 0, cmd);
636
637 res = g_new0(struct virtio_gpu_simple_resource, 1);
638
639 res->resource_id = cblob.resource_id;
640 res->blob_size = cblob.size;
641
642 if (cblob.blob_mem != VIRTIO_GPU_BLOB_MEM_HOST3D) {
643 result = virtio_gpu_create_mapping_iov(g, cblob.nr_entries,
644 sizeof(cblob), cmd, &res->addrs,
645 &res->iov, &res->iov_cnt);
646 CHECK(!result, cmd);
647 }
648
649 rc_blob.blob_id = cblob.blob_id;
650 rc_blob.blob_mem = cblob.blob_mem;
651 rc_blob.blob_flags = cblob.blob_flags;
652 rc_blob.size = cblob.size;
653
654 vecs.iovecs = res->iov;
655 vecs.num_iovecs = res->iov_cnt;
656
657 result = rutabaga_resource_create_blob(vr->rutabaga, cblob.hdr.ctx_id,
658 cblob.resource_id, &rc_blob, &vecs,
659 NULL);
660
661 if (result && cblob.blob_mem != VIRTIO_GPU_BLOB_MEM_HOST3D) {
662 virtio_gpu_cleanup_mapping(g, res);
663 }
664
665 CHECK(!result, cmd);
666
667 QTAILQ_INSERT_HEAD(&g->reslist, res, next);
668 res = NULL;
669 }
670
671 static void
672 rutabaga_cmd_resource_map_blob(VirtIOGPU *g,
673 struct virtio_gpu_ctrl_command *cmd)
674 {
675 int32_t result;
676 uint32_t map_info = 0;
677 uint32_t slot = 0;
678 struct virtio_gpu_simple_resource *res;
679 struct rutabaga_mapping mapping = { 0 };
680 struct virtio_gpu_resource_map_blob mblob;
681 struct virtio_gpu_resp_map_info resp = { 0 };
682
683 VirtIOGPUBase *vb = VIRTIO_GPU_BASE(g);
684 VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
685
686 VIRTIO_GPU_FILL_CMD(mblob);
687
688 CHECK(mblob.resource_id != 0, cmd);
689
690 res = virtio_gpu_find_resource(g, mblob.resource_id);
691 CHECK(res, cmd);
692
693 result = rutabaga_resource_map_info(vr->rutabaga, mblob.resource_id,
694 &map_info);
695 CHECK(!result, cmd);
696
697 /*
698 * RUTABAGA_MAP_ACCESS_* flags are not part of the virtio-gpu spec, but do
699 * exist to potentially allow the hypervisor to restrict write access to
700 * memory. QEMU does not need to use this functionality at the moment.
701 */
702 resp.map_info = map_info & RUTABAGA_MAP_CACHE_MASK;
703
704 result = rutabaga_resource_map(vr->rutabaga, mblob.resource_id, &mapping);
705 CHECK(!result, cmd);
706
707 /*
708 * There is small risk of the MemoryRegion dereferencing the pointer after
709 * rutabaga unmaps it. Please see discussion here:
710 *
711 * https://lists.gnu.org/archive/html/qemu-devel/2023-09/msg05141.html
712 *
713 * It is highly unlikely to happen in practice and doesn't affect known
714 * use cases. However, it should be fixed and is noted here for posterity.
715 */
716 for (slot = 0; slot < MAX_SLOTS; slot++) {
717 if (vr->memory_regions[slot].used) {
718 continue;
719 }
720
721 MemoryRegion *mr = &(vr->memory_regions[slot].mr);
722 memory_region_init_ram_ptr(mr, OBJECT(vr), "blob", mapping.size,
723 mapping.ptr);
724 memory_region_add_subregion(&vb->hostmem, mblob.offset, mr);
725 vr->memory_regions[slot].resource_id = mblob.resource_id;
726 vr->memory_regions[slot].used = 1;
727 break;
728 }
729
730 if (slot >= MAX_SLOTS) {
731 result = rutabaga_resource_unmap(vr->rutabaga, mblob.resource_id);
732 CHECK(!result, cmd);
733 }
734
735 CHECK(slot < MAX_SLOTS, cmd);
736
737 resp.hdr.type = VIRTIO_GPU_RESP_OK_MAP_INFO;
738 virtio_gpu_ctrl_response(g, cmd, &resp.hdr, sizeof(resp));
739 }
740
741 static void
742 rutabaga_cmd_resource_unmap_blob(VirtIOGPU *g,
743 struct virtio_gpu_ctrl_command *cmd)
744 {
745 int32_t result;
746 uint32_t slot = 0;
747 struct virtio_gpu_simple_resource *res;
748 struct virtio_gpu_resource_unmap_blob ublob;
749
750 VirtIOGPUBase *vb = VIRTIO_GPU_BASE(g);
751 VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
752
753 VIRTIO_GPU_FILL_CMD(ublob);
754
755 CHECK(ublob.resource_id != 0, cmd);
756
757 res = virtio_gpu_find_resource(g, ublob.resource_id);
758 CHECK(res, cmd);
759
760 for (slot = 0; slot < MAX_SLOTS; slot++) {
761 if (vr->memory_regions[slot].resource_id != ublob.resource_id) {
762 continue;
763 }
764
765 MemoryRegion *mr = &(vr->memory_regions[slot].mr);
766 memory_region_del_subregion(&vb->hostmem, mr);
767
768 vr->memory_regions[slot].resource_id = 0;
769 vr->memory_regions[slot].used = 0;
770 break;
771 }
772
773 CHECK(slot < MAX_SLOTS, cmd);
774 result = rutabaga_resource_unmap(vr->rutabaga, res->resource_id);
775 CHECK(!result, cmd);
776 }
777
778 static void
779 virtio_gpu_rutabaga_process_cmd(VirtIOGPU *g,
780 struct virtio_gpu_ctrl_command *cmd)
781 {
782 struct rutabaga_fence fence = { 0 };
783 int32_t result;
784
785 VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
786
787 VIRTIO_GPU_FILL_CMD(cmd->cmd_hdr);
788
789 switch (cmd->cmd_hdr.type) {
790 case VIRTIO_GPU_CMD_CTX_CREATE:
791 rutabaga_cmd_context_create(g, cmd);
792 break;
793 case VIRTIO_GPU_CMD_CTX_DESTROY:
794 rutabaga_cmd_context_destroy(g, cmd);
795 break;
796 case VIRTIO_GPU_CMD_RESOURCE_CREATE_2D:
797 rutabaga_cmd_create_resource_2d(g, cmd);
798 break;
799 case VIRTIO_GPU_CMD_RESOURCE_CREATE_3D:
800 rutabaga_cmd_create_resource_3d(g, cmd);
801 break;
802 case VIRTIO_GPU_CMD_SUBMIT_3D:
803 rutabaga_cmd_submit_3d(g, cmd);
804 break;
805 case VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D:
806 rutabaga_cmd_transfer_to_host_2d(g, cmd);
807 break;
808 case VIRTIO_GPU_CMD_TRANSFER_TO_HOST_3D:
809 rutabaga_cmd_transfer_to_host_3d(g, cmd);
810 break;
811 case VIRTIO_GPU_CMD_TRANSFER_FROM_HOST_3D:
812 rutabaga_cmd_transfer_from_host_3d(g, cmd);
813 break;
814 case VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING:
815 rutabaga_cmd_attach_backing(g, cmd);
816 break;
817 case VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING:
818 rutabaga_cmd_detach_backing(g, cmd);
819 break;
820 case VIRTIO_GPU_CMD_SET_SCANOUT:
821 rutabaga_cmd_set_scanout(g, cmd);
822 break;
823 case VIRTIO_GPU_CMD_RESOURCE_FLUSH:
824 rutabaga_cmd_resource_flush(g, cmd);
825 break;
826 case VIRTIO_GPU_CMD_RESOURCE_UNREF:
827 rutabaga_cmd_resource_unref(g, cmd);
828 break;
829 case VIRTIO_GPU_CMD_CTX_ATTACH_RESOURCE:
830 rutabaga_cmd_ctx_attach_resource(g, cmd);
831 break;
832 case VIRTIO_GPU_CMD_CTX_DETACH_RESOURCE:
833 rutabaga_cmd_ctx_detach_resource(g, cmd);
834 break;
835 case VIRTIO_GPU_CMD_GET_CAPSET_INFO:
836 rutabaga_cmd_get_capset_info(g, cmd);
837 break;
838 case VIRTIO_GPU_CMD_GET_CAPSET:
839 rutabaga_cmd_get_capset(g, cmd);
840 break;
841 case VIRTIO_GPU_CMD_GET_DISPLAY_INFO:
842 virtio_gpu_get_display_info(g, cmd);
843 break;
844 case VIRTIO_GPU_CMD_GET_EDID:
845 virtio_gpu_get_edid(g, cmd);
846 break;
847 case VIRTIO_GPU_CMD_RESOURCE_CREATE_BLOB:
848 rutabaga_cmd_resource_create_blob(g, cmd);
849 break;
850 case VIRTIO_GPU_CMD_RESOURCE_MAP_BLOB:
851 rutabaga_cmd_resource_map_blob(g, cmd);
852 break;
853 case VIRTIO_GPU_CMD_RESOURCE_UNMAP_BLOB:
854 rutabaga_cmd_resource_unmap_blob(g, cmd);
855 break;
856 default:
857 cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
858 break;
859 }
860
861 if (cmd->finished) {
862 return;
863 }
864 if (cmd->error) {
865 error_report("%s: ctrl 0x%x, error 0x%x", __func__,
866 cmd->cmd_hdr.type, cmd->error);
867 virtio_gpu_ctrl_response_nodata(g, cmd, cmd->error);
868 return;
869 }
870 if (!(cmd->cmd_hdr.flags & VIRTIO_GPU_FLAG_FENCE)) {
871 virtio_gpu_ctrl_response_nodata(g, cmd, VIRTIO_GPU_RESP_OK_NODATA);
872 return;
873 }
874
875 fence.flags = cmd->cmd_hdr.flags;
876 fence.ctx_id = cmd->cmd_hdr.ctx_id;
877 fence.fence_id = cmd->cmd_hdr.fence_id;
878 fence.ring_idx = cmd->cmd_hdr.ring_idx;
879
880 trace_virtio_gpu_fence_ctrl(cmd->cmd_hdr.fence_id, cmd->cmd_hdr.type);
881
882 result = rutabaga_create_fence(vr->rutabaga, &fence);
883 CHECK(!result, cmd);
884 }
885
886 static void
887 virtio_gpu_rutabaga_aio_cb(void *opaque)
888 {
889 struct rutabaga_aio_data *data = opaque;
890 VirtIOGPU *g = VIRTIO_GPU(data->vr);
891 struct rutabaga_fence fence_data = data->fence;
892 struct virtio_gpu_ctrl_command *cmd, *tmp;
893
894 uint32_t signaled_ctx_specific = fence_data.flags &
895 RUTABAGA_FLAG_INFO_RING_IDX;
896
897 QTAILQ_FOREACH_SAFE(cmd, &g->fenceq, next, tmp) {
898 /*
899 * Due to context specific timelines.
900 */
901 uint32_t target_ctx_specific = cmd->cmd_hdr.flags &
902 RUTABAGA_FLAG_INFO_RING_IDX;
903
904 if (signaled_ctx_specific != target_ctx_specific) {
905 continue;
906 }
907
908 if (signaled_ctx_specific &&
909 (cmd->cmd_hdr.ring_idx != fence_data.ring_idx)) {
910 continue;
911 }
912
913 if (cmd->cmd_hdr.fence_id > fence_data.fence_id) {
914 continue;
915 }
916
917 trace_virtio_gpu_fence_resp(cmd->cmd_hdr.fence_id);
918 virtio_gpu_ctrl_response_nodata(g, cmd, VIRTIO_GPU_RESP_OK_NODATA);
919 QTAILQ_REMOVE(&g->fenceq, cmd, next);
920 g_free(cmd);
921 }
922
923 g_free(data);
924 }
925
926 static void
927 virtio_gpu_rutabaga_fence_cb(uint64_t user_data,
928 const struct rutabaga_fence *fence)
929 {
930 struct rutabaga_aio_data *data;
931 VirtIOGPU *g = (VirtIOGPU *)user_data;
932 VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
933
934 /*
935 * gfxstream and both cross-domain (and even newer versions virglrenderer:
936 * see VIRGL_RENDERER_ASYNC_FENCE_CB) like to signal fence completion on
937 * threads ("callback threads") that are different from the thread that
938 * processes the command queue ("main thread").
939 *
940 * crosvm and other virtio-gpu 1.1 implementations enable callback threads
941 * via locking. However, on QEMU a deadlock is observed if
942 * virtio_gpu_ctrl_response_nodata(..) [used in the fence callback] is used
943 * from a thread that is not the main thread.
944 *
945 * The reason is QEMU's internal locking is designed to work with QEMU
946 * threads (see rcu_register_thread()) and not generic C/C++/Rust threads.
947 * For now, we can workaround this by scheduling the return of the
948 * fence descriptors on the main thread.
949 */
950
951 data = g_new0(struct rutabaga_aio_data, 1);
952 data->vr = vr;
953 data->fence = *fence;
954 aio_bh_schedule_oneshot(qemu_get_aio_context(),
955 virtio_gpu_rutabaga_aio_cb,
956 data);
957 }
958
959 static void
960 virtio_gpu_rutabaga_debug_cb(uint64_t user_data,
961 const struct rutabaga_debug *debug)
962 {
963 switch (debug->debug_type) {
964 case RUTABAGA_DEBUG_ERROR:
965 error_report("%s", debug->message);
966 break;
967 case RUTABAGA_DEBUG_WARN:
968 warn_report("%s", debug->message);
969 break;
970 case RUTABAGA_DEBUG_INFO:
971 info_report("%s", debug->message);
972 break;
973 default:
974 error_report("unknown debug type: %u", debug->debug_type);
975 }
976 }
977
978 static bool virtio_gpu_rutabaga_init(VirtIOGPU *g, Error **errp)
979 {
980 int result;
981 struct rutabaga_builder builder = { 0 };
982 struct rutabaga_channel channel = { 0 };
983 struct rutabaga_channels channels = { 0 };
984
985 VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
986 vr->rutabaga = NULL;
987
988 builder.wsi = RUTABAGA_WSI_SURFACELESS;
989 /*
990 * Currently, if WSI is specified, the only valid strings are "surfaceless"
991 * or "headless". Surfaceless doesn't create a native window surface, but
992 * does copy from the render target to the Pixman buffer if a virtio-gpu
993 * 2D hypercall is issued. Surfacless is the default.
994 *
995 * Headless is like surfaceless, but doesn't copy to the Pixman buffer. The
996 * use case is automated testing environments where there is no need to view
997 * results.
998 *
999 * In the future, more performant virtio-gpu 2D UI integration may be added.
1000 */
1001 if (vr->wsi) {
1002 if (g_str_equal(vr->wsi, "surfaceless")) {
1003 vr->headless = false;
1004 } else if (g_str_equal(vr->wsi, "headless")) {
1005 vr->headless = true;
1006 } else {
1007 error_setg(errp, "invalid wsi option selected");
1008 return false;
1009 }
1010 }
1011
1012 builder.fence_cb = virtio_gpu_rutabaga_fence_cb;
1013 builder.debug_cb = virtio_gpu_rutabaga_debug_cb;
1014 builder.capset_mask = vr->capset_mask;
1015 builder.user_data = (uint64_t)g;
1016
1017 /*
1018 * If the user doesn't specify the wayland socket path, we try to infer
1019 * the socket via a process similar to the one used by libwayland.
1020 * libwayland does the following:
1021 *
1022 * 1) If $WAYLAND_DISPLAY is set, attempt to connect to
1023 * $XDG_RUNTIME_DIR/$WAYLAND_DISPLAY
1024 * 2) Otherwise, attempt to connect to $XDG_RUNTIME_DIR/wayland-0
1025 * 3) Otherwise, don't pass a wayland socket to rutabaga. If a guest
1026 * wayland proxy is launched, it will fail to work.
1027 */
1028 channel.channel_type = RUTABAGA_CHANNEL_TYPE_WAYLAND;
1029 g_autofree gchar *path = NULL;
1030 if (!vr->wayland_socket_path) {
1031 const gchar *runtime_dir = g_get_user_runtime_dir();
1032 const gchar *display = g_getenv("WAYLAND_DISPLAY");
1033 if (!display) {
1034 display = "wayland-0";
1035 }
1036
1037 if (runtime_dir) {
1038 path = g_build_filename(runtime_dir, display, NULL);
1039 channel.channel_name = path;
1040 }
1041 } else {
1042 channel.channel_name = vr->wayland_socket_path;
1043 }
1044
1045 if ((builder.capset_mask & (1 << RUTABAGA_CAPSET_CROSS_DOMAIN))) {
1046 if (channel.channel_name) {
1047 channels.channels = &channel;
1048 channels.num_channels = 1;
1049 builder.channels = &channels;
1050 }
1051 }
1052
1053 result = rutabaga_init(&builder, &vr->rutabaga);
1054 if (result) {
1055 error_setg_errno(errp, -result, "Failed to init rutabaga");
1056 return false;
1057 }
1058
1059 return true;
1060 }
1061
1062 static bool
1063 virtio_gpu_rutabaga_get_num_capsets(VirtIOGPU *g, uint32_t *num_capsets, Error **errp)
1064 {
1065 int result;
1066 VirtIOGPURutabaga *vr = VIRTIO_GPU_RUTABAGA(g);
1067
1068 result = rutabaga_get_num_capsets(vr->rutabaga, num_capsets);
1069 if (result) {
1070 error_setg_errno(errp, -result, "Failed to get num_capsets");
1071 return false;
1072 }
1073 vr->num_capsets = *num_capsets;
1074 return true;
1075 }
1076
1077 static void virtio_gpu_rutabaga_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
1078 {
1079 VirtIOGPU *g = VIRTIO_GPU(vdev);
1080 struct virtio_gpu_ctrl_command *cmd;
1081
1082 if (!virtio_queue_ready(vq)) {
1083 return;
1084 }
1085
1086 cmd = virtqueue_pop(vq, sizeof(struct virtio_gpu_ctrl_command));
1087 while (cmd) {
1088 cmd->vq = vq;
1089 cmd->error = 0;
1090 cmd->finished = false;
1091 QTAILQ_INSERT_TAIL(&g->cmdq, cmd, next);
1092 cmd = virtqueue_pop(vq, sizeof(struct virtio_gpu_ctrl_command));
1093 }
1094
1095 virtio_gpu_process_cmdq(g);
1096 }
1097
1098 static void virtio_gpu_rutabaga_realize(DeviceState *qdev, Error **errp)
1099 {
1100 ERRP_GUARD();
1101 uint32_t num_capsets;
1102 VirtIOGPUBase *bdev = VIRTIO_GPU_BASE(qdev);
1103 VirtIOGPU *gpudev = VIRTIO_GPU(qdev);
1104
1105 #if HOST_BIG_ENDIAN
1106 error_setg(errp, "rutabaga is not supported on bigendian platforms");
1107 return;
1108 #endif
1109
1110 error_setg(&bdev->migration_blocker, "rutabaga is not yet migratable");
1111 if (migrate_add_blocker(&bdev->migration_blocker, errp) < 0) {
1112 return;
1113 }
1114
1115 if (!virtio_gpu_rutabaga_init(gpudev, errp)) {
1116 goto fail;
1117 }
1118
1119 if (!virtio_gpu_rutabaga_get_num_capsets(gpudev, &num_capsets, errp)) {
1120 goto fail;
1121 }
1122
1123 bdev->conf.flags |= (1 << VIRTIO_GPU_FLAG_RUTABAGA_ENABLED);
1124 bdev->conf.flags |= (1 << VIRTIO_GPU_FLAG_BLOB_ENABLED);
1125 bdev->conf.flags |= (1 << VIRTIO_GPU_FLAG_CONTEXT_INIT_ENABLED);
1126
1127 bdev->virtio_config.num_capsets = num_capsets;
1128 virtio_gpu_device_realize(qdev, errp);
1129 if (!*errp) {
1130 return;
1131 }
1132
1133 fail:
1134 migrate_del_blocker(&bdev->migration_blocker);
1135 }
1136
1137 static const Property virtio_gpu_rutabaga_properties[] = {
1138 DEFINE_PROP_BIT64("gfxstream-vulkan", VirtIOGPURutabaga, capset_mask,
1139 RUTABAGA_CAPSET_GFXSTREAM_VULKAN, false),
1140 DEFINE_PROP_BIT64("cross-domain", VirtIOGPURutabaga, capset_mask,
1141 RUTABAGA_CAPSET_CROSS_DOMAIN, false),
1142 DEFINE_PROP_BIT64("x-gfxstream-gles", VirtIOGPURutabaga, capset_mask,
1143 RUTABAGA_CAPSET_GFXSTREAM_GLES, false),
1144 DEFINE_PROP_BIT64("x-gfxstream-composer", VirtIOGPURutabaga, capset_mask,
1145 RUTABAGA_CAPSET_GFXSTREAM_COMPOSER, false),
1146 DEFINE_PROP_STRING("wayland-socket-path", VirtIOGPURutabaga,
1147 wayland_socket_path),
1148 DEFINE_PROP_STRING("wsi", VirtIOGPURutabaga, wsi),
1149 };
1150
1151 static void virtio_gpu_rutabaga_class_init(ObjectClass *klass, const void *data)
1152 {
1153 DeviceClass *dc = DEVICE_CLASS(klass);
1154 VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
1155 VirtIOGPUBaseClass *vbc = VIRTIO_GPU_BASE_CLASS(klass);
1156 VirtIOGPUClass *vgc = VIRTIO_GPU_CLASS(klass);
1157
1158 vbc->gl_flushed = virtio_gpu_rutabaga_gl_flushed;
1159 vgc->handle_ctrl = virtio_gpu_rutabaga_handle_ctrl;
1160 vgc->process_cmd = virtio_gpu_rutabaga_process_cmd;
1161 vgc->update_cursor_data = virtio_gpu_rutabaga_update_cursor;
1162 vgc->resource_destroy = virtio_gpu_rutabaga_resource_unref;
1163 vdc->realize = virtio_gpu_rutabaga_realize;
1164 device_class_set_props(dc, virtio_gpu_rutabaga_properties);
1165 }
1166
1167 static const TypeInfo virtio_gpu_rutabaga_info[] = {
1168 {
1169 .name = TYPE_VIRTIO_GPU_RUTABAGA,
1170 .parent = TYPE_VIRTIO_GPU,
1171 .instance_size = sizeof(VirtIOGPURutabaga),
1172 .class_init = virtio_gpu_rutabaga_class_init,
1173 },
1174 };
1175
1176 DEFINE_TYPES(virtio_gpu_rutabaga_info)
1177
1178 module_obj(TYPE_VIRTIO_GPU_RUTABAGA);
1179 module_kconfig(VIRTIO_GPU);
1180 module_dep("hw-display-virtio-gpu");