1 /**************************************************************************
2 *
3 * Copyright (C) 2015 Red Hat Inc.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included
13 * in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
19 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21 * OTHER DEALINGS IN THE SOFTWARE.
22 *
23 **************************************************************************/
24
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <fcntl.h>
30 #include <limits.h>
31
32 #include "virgl_hw.h"
33 #include "virglrenderer.h"
34
35 #include <sys/uio.h>
36 #include <sys/socket.h>
37 #include <sys/mman.h>
38
39 #include "vtest.h"
40 #include "vtest_shm.h"
41 #include "vtest_protocol.h"
42
43 #include "util.h"
44 #include "util/u_debug.h"
45 #include "util/u_double_list.h"
46 #include "util/u_math.h"
47 #include "util/u_memory.h"
48 #include "util/u_hash_table.h"
49
50 struct vtest_resource {
51 uint32_t res_id;
52
53 struct iovec iov;
54 };
55
56 struct vtest_context {
57 struct list_head head;
58
59 int ctx_id;
60
61 struct vtest_input *input;
62 int out_fd;
63
64 char *debug_name;
65
66 unsigned protocol_version;
67 unsigned capset_id;
68 bool context_initialized;
69
70 struct util_hash_table *resource_table;
71 };
72
73 struct vtest_renderer {
74 const char *rendernode_name;
75
76 uint32_t max_length;
77
78 int fence_id;
79 int last_fence;
80
81 struct list_head active_contexts;
82 struct list_head free_contexts;
83 int next_context_id;
84
85 struct vtest_context *current_context;
86 };
87
vtest_write_fence(UNUSED void * cookie,uint32_t fence_id_in)88 static void vtest_write_fence(UNUSED void *cookie, uint32_t fence_id_in)
89 {
90 struct vtest_renderer *renderer = (struct vtest_renderer*)cookie;
91 renderer->last_fence = fence_id_in;
92 }
93
vtest_get_drm_fd(void * cookie)94 static int vtest_get_drm_fd(void *cookie)
95 {
96 int fd = -1;
97 struct vtest_renderer *renderer = (struct vtest_renderer*)cookie;
98 if (!renderer->rendernode_name)
99 return -1;
100 fd = open(renderer->rendernode_name, O_RDWR | O_CLOEXEC | O_NOCTTY | O_NONBLOCK);
101 if (fd == -1)
102 fprintf(stderr, "Unable to open rendernode '%s' falling back to default search\n",
103 renderer->rendernode_name);
104 return fd;
105 }
106
107 static struct virgl_renderer_callbacks renderer_cbs = {
108 .version = 2,
109 .write_fence = vtest_write_fence,
110 .get_drm_fd = vtest_get_drm_fd
111 };
112
113
114 static struct vtest_renderer renderer = {
115 .max_length = UINT_MAX,
116 .fence_id = 1,
117 .next_context_id = 1,
118 };
119
120 static unsigned
resource_hash_func(void * key)121 resource_hash_func(void *key)
122 {
123 intptr_t ip = pointer_to_intptr(key);
124 return (unsigned)(ip & 0xffffffff);
125 }
126
127 static int
resource_compare_func(void * key1,void * key2)128 resource_compare_func(void *key1, void *key2)
129 {
130 if (key1 < key2) {
131 return -1;
132 } else if (key1 > key2) {
133 return 1;
134 } else {
135 return 0;
136 }
137 }
138
139 static void
resource_destroy_func(void * value)140 resource_destroy_func(void *value)
141 {
142 struct vtest_resource *res = value;
143
144 /* virgl_renderer_ctx_detach_resource and virgl_renderer_resource_detach_iov
145 * are implied
146 */
147 virgl_renderer_resource_unref(res->res_id);
148
149 if (res->iov.iov_base)
150 munmap(res->iov.iov_base, res->iov.iov_len);
151 free(res);
152 }
153
vtest_block_write(int fd,void * buf,int size)154 static int vtest_block_write(int fd, void *buf, int size)
155 {
156 char *ptr = buf;
157 int left;
158 int ret;
159 left = size;
160
161 do {
162 ret = write(fd, ptr, left);
163 if (ret < 0) {
164 return -errno;
165 }
166
167 left -= ret;
168 ptr += ret;
169 } while (left);
170
171 return size;
172 }
173
vtest_block_read(struct vtest_input * input,void * buf,int size)174 int vtest_block_read(struct vtest_input *input, void *buf, int size)
175 {
176 int fd = input->data.fd;
177 char *ptr = buf;
178 int left;
179 int ret;
180 static int savefd = -1;
181
182 left = size;
183 do {
184 ret = read(fd, ptr, left);
185 if (ret <= 0) {
186 return ret == -1 ? -errno : 0;
187 }
188
189 left -= ret;
190 ptr += ret;
191 } while (left);
192
193 if (getenv("VTEST_SAVE")) {
194 if (savefd == -1) {
195 savefd = open(getenv("VTEST_SAVE"),
196 O_CLOEXEC|O_CREAT|O_WRONLY|O_TRUNC|O_DSYNC, S_IRUSR|S_IWUSR);
197 if (savefd == -1) {
198 perror("error opening save file");
199 exit(1);
200 }
201 }
202 if (write(savefd, buf, size) != size) {
203 perror("failed to save");
204 exit(1);
205 }
206 }
207
208 return size;
209 }
210
vtest_send_fd(int socket_fd,int fd)211 static int vtest_send_fd(int socket_fd, int fd)
212 {
213 struct iovec iovec;
214 char buf[CMSG_SPACE(sizeof(int))];
215 char c = 0;
216 struct msghdr msgh = { 0 };
217 memset(buf, 0, sizeof(buf));
218
219 iovec.iov_base = &c;
220 iovec.iov_len = sizeof(char);
221
222 msgh.msg_name = NULL;
223 msgh.msg_namelen = 0;
224 msgh.msg_iov = &iovec;
225 msgh.msg_iovlen = 1;
226 msgh.msg_control = buf;
227 msgh.msg_controllen = sizeof(buf);
228 msgh.msg_flags = 0;
229
230 struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msgh);
231 cmsg->cmsg_level = SOL_SOCKET;
232 cmsg->cmsg_type = SCM_RIGHTS;
233 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
234
235 *((int *) CMSG_DATA(cmsg)) = fd;
236
237 int size = sendmsg(socket_fd, &msgh, 0);
238 if (size < 0) {
239 return report_failure("Failed to send fd", -EINVAL);
240 }
241
242 return 0;
243 }
244
vtest_buf_read(struct vtest_input * input,void * buf,int size)245 int vtest_buf_read(struct vtest_input *input, void *buf, int size)
246 {
247 struct vtest_buffer *inbuf = input->data.buffer;
248 if (size > inbuf->size) {
249 return 0;
250 }
251
252 memcpy(buf, inbuf->buffer, size);
253 inbuf->buffer += size;
254 inbuf->size -= size;
255
256 return size;
257 }
258
vtest_init_renderer(int ctx_flags,const char * render_device)259 int vtest_init_renderer(int ctx_flags, const char *render_device)
260 {
261 int ret;
262
263 renderer.rendernode_name = render_device;
264 list_inithead(&renderer.active_contexts);
265 list_inithead(&renderer.free_contexts);
266
267 ret = virgl_renderer_init(&renderer,
268 ctx_flags | VIRGL_RENDERER_THREAD_SYNC, &renderer_cbs);
269 if (ret) {
270 fprintf(stderr, "failed to initialise renderer.\n");
271 return -1;
272 }
273
274 return 0;
275 }
276
277 static void vtest_free_context(struct vtest_context *ctx, bool cleanup);
278
vtest_cleanup_renderer(void)279 void vtest_cleanup_renderer(void)
280 {
281 if (renderer.next_context_id > 1) {
282 struct vtest_context *ctx, *tmp;
283
284 LIST_FOR_EACH_ENTRY_SAFE(ctx, tmp, &renderer.active_contexts, head) {
285 vtest_destroy_context(ctx);
286 }
287 LIST_FOR_EACH_ENTRY_SAFE(ctx, tmp, &renderer.free_contexts, head) {
288 vtest_free_context(ctx, true);
289 }
290 list_inithead(&renderer.active_contexts);
291 list_inithead(&renderer.free_contexts);
292
293 renderer.next_context_id = 1;
294 renderer.current_context = NULL;
295 }
296
297 virgl_renderer_cleanup(&renderer);
298 }
299
vtest_new_context(struct vtest_input * input,int out_fd)300 static struct vtest_context *vtest_new_context(struct vtest_input *input,
301 int out_fd)
302 {
303 struct vtest_context *ctx;
304
305 if (LIST_IS_EMPTY(&renderer.free_contexts)) {
306 ctx = malloc(sizeof(*ctx));
307 if (!ctx) {
308 return NULL;
309 }
310
311 ctx->resource_table = util_hash_table_create(resource_hash_func,
312 resource_compare_func,
313 resource_destroy_func);
314 if (!ctx->resource_table) {
315 free(ctx);
316 return NULL;
317 }
318
319 ctx->ctx_id = renderer.next_context_id++;
320 } else {
321 ctx = LIST_ENTRY(struct vtest_context, renderer.free_contexts.next, head);
322 list_del(&ctx->head);
323 }
324
325 ctx->input = input;
326 ctx->out_fd = out_fd;
327
328 ctx->debug_name = NULL;
329 /* By default we support version 0 unless VCMD_PROTOCOL_VERSION is sent */
330 ctx->protocol_version = 0;
331 ctx->capset_id = 0;
332 ctx->context_initialized = false;
333
334 return ctx;
335 }
336
vtest_free_context(struct vtest_context * ctx,bool cleanup)337 static void vtest_free_context(struct vtest_context *ctx, bool cleanup)
338 {
339 if (cleanup) {
340 util_hash_table_destroy(ctx->resource_table);
341 free(ctx);
342 } else {
343 list_add(&ctx->head, &renderer.free_contexts);
344 }
345 }
346
vtest_create_context(struct vtest_input * input,int out_fd,uint32_t length,struct vtest_context ** out_ctx)347 int vtest_create_context(struct vtest_input *input, int out_fd,
348 uint32_t length, struct vtest_context **out_ctx)
349 {
350 struct vtest_context *ctx;
351 char *vtestname;
352 int ret;
353
354 if (length > 1024 * 1024) {
355 return -1;
356 }
357
358 ctx = vtest_new_context(input, out_fd);
359 if (!ctx) {
360 return -1;
361 }
362
363 vtestname = calloc(1, length + 1);
364 if (!vtestname) {
365 ret = -1;
366 goto err;
367 }
368
369 ret = ctx->input->read(ctx->input, vtestname, length);
370 if (ret != (int)length) {
371 ret = -1;
372 goto err;
373 }
374
375 ctx->debug_name = vtestname;
376
377 list_addtail(&ctx->head, &renderer.active_contexts);
378 *out_ctx = ctx;
379
380 return 0;
381
382 err:
383 free(vtestname);
384 vtest_free_context(ctx, false);
385 return ret;
386 }
387
vtest_lazy_init_context(struct vtest_context * ctx)388 int vtest_lazy_init_context(struct vtest_context *ctx)
389 {
390 int ret;
391
392 if (ctx->context_initialized)
393 return 0;
394
395 if (ctx->capset_id) {
396 ret = virgl_renderer_context_create_with_flags(ctx->ctx_id,
397 ctx->capset_id,
398 strlen(ctx->debug_name),
399 ctx->debug_name);
400 } else {
401 ret = virgl_renderer_context_create(ctx->ctx_id,
402 strlen(ctx->debug_name),
403 ctx->debug_name);
404 }
405 ctx->context_initialized = (ret == 0);
406
407 return ret;
408 }
409
vtest_destroy_context(struct vtest_context * ctx)410 void vtest_destroy_context(struct vtest_context *ctx)
411 {
412 if (renderer.current_context == ctx) {
413 renderer.current_context = NULL;
414 }
415 list_del(&ctx->head);
416
417 free(ctx->debug_name);
418 if (ctx->context_initialized)
419 virgl_renderer_context_destroy(ctx->ctx_id);
420 util_hash_table_clear(ctx->resource_table);
421 vtest_free_context(ctx, false);
422 }
423
vtest_set_current_context(struct vtest_context * ctx)424 void vtest_set_current_context(struct vtest_context *ctx)
425 {
426 renderer.current_context = ctx;
427 }
428
vtest_get_current_context(void)429 static struct vtest_context *vtest_get_current_context(void)
430 {
431 return renderer.current_context;
432 }
433
vtest_ping_protocol_version(UNUSED uint32_t length_dw)434 int vtest_ping_protocol_version(UNUSED uint32_t length_dw)
435 {
436 struct vtest_context *ctx = vtest_get_current_context();
437 uint32_t hdr_buf[VTEST_HDR_SIZE];
438 int ret;
439
440 hdr_buf[VTEST_CMD_LEN] = VCMD_PING_PROTOCOL_VERSION_SIZE;
441 hdr_buf[VTEST_CMD_ID] = VCMD_PING_PROTOCOL_VERSION;
442 ret = vtest_block_write(ctx->out_fd, hdr_buf, sizeof(hdr_buf));
443 if (ret < 0) {
444 return ret;
445 }
446
447 return 0;
448 }
449
vtest_protocol_version(UNUSED uint32_t length_dw)450 int vtest_protocol_version(UNUSED uint32_t length_dw)
451 {
452 struct vtest_context *ctx = vtest_get_current_context();
453 uint32_t hdr_buf[VTEST_HDR_SIZE];
454 uint32_t version_buf[VCMD_PROTOCOL_VERSION_SIZE];
455 unsigned version;
456 int ret;
457
458 ret = ctx->input->read(ctx->input, &version_buf, sizeof(version_buf));
459 if (ret != sizeof(version_buf))
460 return -1;
461
462 version = MIN2(version_buf[VCMD_PROTOCOL_VERSION_VERSION],
463 VTEST_PROTOCOL_VERSION);
464
465 /*
466 * We've deprecated protocol version 1. All of it's called sites are being
467 * moved protocol version 2. If the server supports version 2 and the guest
468 * supports verison 1, fall back to version 0.
469 */
470 if (version == 1) {
471 printf("Older guest Mesa detected, fallbacking to protocol version 0\n");
472 version = 0;
473 }
474
475 /* Protocol version 2 requires shm support. */
476 if (!vtest_shm_check()) {
477 printf("Shared memory not supported, fallbacking to protocol version 0\n");
478 version = 0;
479 }
480
481 ctx->protocol_version = version;
482
483 hdr_buf[VTEST_CMD_LEN] = VCMD_PROTOCOL_VERSION_SIZE;
484 hdr_buf[VTEST_CMD_ID] = VCMD_PROTOCOL_VERSION;
485
486 version_buf[VCMD_PROTOCOL_VERSION_VERSION] = ctx->protocol_version;
487
488 ret = vtest_block_write(ctx->out_fd, hdr_buf, sizeof(hdr_buf));
489 if (ret < 0) {
490 return ret;
491 }
492
493 ret = vtest_block_write(ctx->out_fd, version_buf, sizeof(version_buf));
494 if (ret < 0) {
495 return ret;
496 }
497
498 return 0;
499 }
500
vtest_get_param(UNUSED uint32_t length_dw)501 int vtest_get_param(UNUSED uint32_t length_dw)
502 {
503 struct vtest_context *ctx = vtest_get_current_context();
504 uint32_t get_param_buf[VCMD_GET_PARAM_SIZE];
505 uint32_t resp_buf[VTEST_HDR_SIZE + 2];
506 uint32_t param;
507 uint32_t *resp;
508 int ret;
509
510 ret = ctx->input->read(ctx->input, get_param_buf, sizeof(get_param_buf));
511 if (ret != sizeof(get_param_buf))
512 return -1;
513
514 param = get_param_buf[VCMD_GET_PARAM_PARAM];
515
516 resp_buf[VTEST_CMD_LEN] = 2;
517 resp_buf[VTEST_CMD_ID] = VCMD_GET_PARAM;
518 resp = &resp_buf[VTEST_CMD_DATA_START];
519 switch (param) {
520 default:
521 resp[0] = false;
522 resp[1] = 0;
523 break;
524 }
525
526 ret = vtest_block_write(ctx->out_fd, resp_buf, sizeof(resp_buf));
527 if (ret < 0)
528 return -1;
529
530 return 0;
531 }
532
vtest_get_capset(UNUSED uint32_t length_dw)533 int vtest_get_capset(UNUSED uint32_t length_dw)
534 {
535 struct vtest_context *ctx = vtest_get_current_context();
536 uint32_t get_capset_buf[VCMD_GET_CAPSET_SIZE];
537 uint32_t resp_buf[VTEST_HDR_SIZE + 1];
538 uint32_t id;
539 uint32_t version;
540 uint32_t max_version;
541 uint32_t max_size;
542 void *caps;
543 int ret;
544
545 ret = ctx->input->read(ctx->input, get_capset_buf, sizeof(get_capset_buf));
546 if (ret != sizeof(get_capset_buf))
547 return -1;
548
549 id = get_capset_buf[VCMD_GET_CAPSET_ID];
550 version = get_capset_buf[VCMD_GET_CAPSET_VERSION];
551
552 virgl_renderer_get_cap_set(id, &max_version, &max_size);
553
554 /* unsupported id or version */
555 if ((!max_version && !max_size) || version > max_version) {
556 resp_buf[VTEST_CMD_LEN] = 1;
557 resp_buf[VTEST_CMD_ID] = VCMD_GET_CAPSET;
558 resp_buf[VTEST_CMD_DATA_START] = false;
559 return vtest_block_write(ctx->out_fd, resp_buf, sizeof(resp_buf));
560 }
561
562 if (max_size % 4)
563 return -EINVAL;
564
565 caps = malloc(max_size);
566 if (!caps)
567 return -ENOMEM;
568
569 virgl_renderer_fill_caps(id, version, caps);
570
571 resp_buf[VTEST_CMD_LEN] = 1 + max_size / 4;
572 resp_buf[VTEST_CMD_ID] = VCMD_GET_CAPSET;
573 resp_buf[VTEST_CMD_DATA_START] = true;
574 ret = vtest_block_write(ctx->out_fd, resp_buf, sizeof(resp_buf));
575 if (ret >= 0)
576 ret = vtest_block_write(ctx->out_fd, caps, max_size);
577
578 free(caps);
579 return ret >= 0 ? 0 : ret;
580 }
581
vtest_context_init(UNUSED uint32_t length_dw)582 int vtest_context_init(UNUSED uint32_t length_dw)
583 {
584 struct vtest_context *ctx = vtest_get_current_context();
585 uint32_t context_init_buf[VCMD_CONTEXT_INIT_SIZE];
586 uint32_t capset_id;
587 int ret;
588
589 ret = ctx->input->read(ctx->input, context_init_buf, sizeof(context_init_buf));
590 if (ret != sizeof(context_init_buf))
591 return -1;
592
593 capset_id = context_init_buf[VCMD_CONTEXT_INIT_CAPSET_ID];
594 if (!capset_id)
595 return -EINVAL;
596
597 if (ctx->context_initialized) {
598 return ctx->capset_id == capset_id ? 0 : -EINVAL;
599 }
600
601 ctx->capset_id = capset_id;
602
603 return vtest_lazy_init_context(ctx);
604 }
605
vtest_send_caps2(UNUSED uint32_t length_dw)606 int vtest_send_caps2(UNUSED uint32_t length_dw)
607 {
608 struct vtest_context *ctx = vtest_get_current_context();
609 uint32_t hdr_buf[2];
610 void *caps_buf;
611 int ret;
612 uint32_t max_ver, max_size;
613
614 virgl_renderer_get_cap_set(2, &max_ver, &max_size);
615
616 if (max_size == 0) {
617 return -1;
618 }
619
620 caps_buf = malloc(max_size);
621 if (!caps_buf) {
622 return -1;
623 }
624
625 virgl_renderer_fill_caps(2, 1, caps_buf);
626
627 hdr_buf[0] = max_size + 1;
628 hdr_buf[1] = 2;
629 ret = vtest_block_write(ctx->out_fd, hdr_buf, 8);
630 if (ret < 0) {
631 goto end;
632 }
633
634 vtest_block_write(ctx->out_fd, caps_buf, max_size);
635 if (ret < 0) {
636 goto end;
637 }
638
639 end:
640 free(caps_buf);
641 return 0;
642 }
643
vtest_send_caps(UNUSED uint32_t length_dw)644 int vtest_send_caps(UNUSED uint32_t length_dw)
645 {
646 struct vtest_context *ctx = vtest_get_current_context();
647 uint32_t max_ver, max_size;
648 void *caps_buf;
649 uint32_t hdr_buf[2];
650 int ret;
651
652 virgl_renderer_get_cap_set(1, &max_ver, &max_size);
653
654 caps_buf = malloc(max_size);
655 if (!caps_buf) {
656 return -1;
657 }
658
659 virgl_renderer_fill_caps(1, 1, caps_buf);
660
661 hdr_buf[0] = max_size + 1;
662 hdr_buf[1] = 1;
663 ret = vtest_block_write(ctx->out_fd, hdr_buf, 8);
664 if (ret < 0) {
665 goto end;
666 }
667
668 vtest_block_write(ctx->out_fd, caps_buf, max_size);
669 if (ret < 0) {
670 goto end;
671 }
672
673 end:
674 free(caps_buf);
675 return 0;
676 }
677
vtest_create_resource_decode_args(struct vtest_context * ctx,struct virgl_renderer_resource_create_args * args)678 static int vtest_create_resource_decode_args(struct vtest_context *ctx,
679 struct virgl_renderer_resource_create_args *args)
680 {
681 uint32_t res_create_buf[VCMD_RES_CREATE_SIZE];
682 int ret;
683
684 ret = ctx->input->read(ctx->input, &res_create_buf,
685 sizeof(res_create_buf));
686 if (ret != sizeof(res_create_buf)) {
687 return -1;
688 }
689
690 args->handle = res_create_buf[VCMD_RES_CREATE_RES_HANDLE];
691 args->target = res_create_buf[VCMD_RES_CREATE_TARGET];
692 args->format = res_create_buf[VCMD_RES_CREATE_FORMAT];
693 args->bind = res_create_buf[VCMD_RES_CREATE_BIND];
694
695 args->width = res_create_buf[VCMD_RES_CREATE_WIDTH];
696 args->height = res_create_buf[VCMD_RES_CREATE_HEIGHT];
697 args->depth = res_create_buf[VCMD_RES_CREATE_DEPTH];
698 args->array_size = res_create_buf[VCMD_RES_CREATE_ARRAY_SIZE];
699 args->last_level = res_create_buf[VCMD_RES_CREATE_LAST_LEVEL];
700 args->nr_samples = res_create_buf[VCMD_RES_CREATE_NR_SAMPLES];
701 args->flags = 0;
702
703 return 0;
704 }
705
vtest_create_resource_decode_args2(struct vtest_context * ctx,struct virgl_renderer_resource_create_args * args,size_t * shm_size)706 static int vtest_create_resource_decode_args2(struct vtest_context *ctx,
707 struct virgl_renderer_resource_create_args *args,
708 size_t *shm_size)
709 {
710 uint32_t res_create_buf[VCMD_RES_CREATE2_SIZE];
711 int ret;
712
713 ret = ctx->input->read(ctx->input, &res_create_buf,
714 sizeof(res_create_buf));
715 if (ret != sizeof(res_create_buf)) {
716 return -1;
717 }
718
719 args->handle = res_create_buf[VCMD_RES_CREATE2_RES_HANDLE];
720 args->target = res_create_buf[VCMD_RES_CREATE2_TARGET];
721 args->format = res_create_buf[VCMD_RES_CREATE2_FORMAT];
722 args->bind = res_create_buf[VCMD_RES_CREATE2_BIND];
723
724 args->width = res_create_buf[VCMD_RES_CREATE2_WIDTH];
725 args->height = res_create_buf[VCMD_RES_CREATE2_HEIGHT];
726 args->depth = res_create_buf[VCMD_RES_CREATE2_DEPTH];
727 args->array_size = res_create_buf[VCMD_RES_CREATE2_ARRAY_SIZE];
728 args->last_level = res_create_buf[VCMD_RES_CREATE2_LAST_LEVEL];
729 args->nr_samples = res_create_buf[VCMD_RES_CREATE2_NR_SAMPLES];
730 args->flags = 0;
731
732 *shm_size = res_create_buf[VCMD_RES_CREATE2_DATA_SIZE];
733
734 return 0;
735 }
736
vtest_create_resource_setup_shm(struct vtest_resource * res,size_t size)737 static int vtest_create_resource_setup_shm(struct vtest_resource *res,
738 size_t size)
739 {
740 int fd;
741 void *ptr;
742
743 fd = vtest_new_shm(res->res_id, size);
744 if (fd < 0)
745 return report_failed_call("vtest_new_shm", fd);
746
747 ptr = mmap(NULL, size, PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0);
748 if (ptr == MAP_FAILED) {
749 close(fd);
750 return -1;
751 }
752
753 res->iov.iov_base = ptr;
754 res->iov.iov_len = size;
755
756 return fd;
757 }
758
vtest_create_resource_internal(struct vtest_context * ctx,struct virgl_renderer_resource_create_args * args,size_t shm_size)759 static int vtest_create_resource_internal(struct vtest_context *ctx,
760 struct virgl_renderer_resource_create_args *args,
761 size_t shm_size)
762 {
763 struct vtest_resource *res;
764 int ret;
765
766 // Check that the handle doesn't already exist.
767 if (util_hash_table_get(ctx->resource_table, intptr_to_pointer(args->handle)))
768 return -EEXIST;
769
770 ret = virgl_renderer_resource_create(args, NULL, 0);
771 if (ret)
772 return report_failed_call("virgl_renderer_resource_create", ret);
773
774 virgl_renderer_ctx_attach_resource(ctx->ctx_id, args->handle);
775
776 res = CALLOC_STRUCT(vtest_resource);
777 if (!res)
778 return -ENOMEM;
779 res->res_id = args->handle;
780
781 /* no shm for v1 resources or v2 multi-sample resources */
782 if (shm_size) {
783 int fd;
784
785 fd = vtest_create_resource_setup_shm(res, shm_size);
786 if (fd < 0) {
787 FREE(res);
788 return -ENOMEM;
789 }
790
791 ret = vtest_send_fd(ctx->out_fd, fd);
792 if (ret < 0) {
793 munmap(res->iov.iov_base, res->iov.iov_len);
794 close(fd);
795 FREE(res);
796 return report_failed_call("vtest_send_fd", ret);
797 }
798
799 /* Closing the file descriptor does not unmap the region. */
800 close(fd);
801
802 virgl_renderer_resource_attach_iov(args->handle, &res->iov, 1);
803 }
804
805 util_hash_table_set(ctx->resource_table, intptr_to_pointer(res->res_id), res);
806
807 return 0;
808 }
809
vtest_create_resource(UNUSED uint32_t length_dw)810 int vtest_create_resource(UNUSED uint32_t length_dw)
811 {
812 struct vtest_context *ctx = vtest_get_current_context();
813 struct virgl_renderer_resource_create_args args;
814 int ret;
815
816 ret = vtest_create_resource_decode_args(ctx, &args);
817 if (ret < 0) {
818 return ret;
819 }
820
821 return vtest_create_resource_internal(ctx, &args, 0);
822 }
823
vtest_create_resource2(UNUSED uint32_t length_dw)824 int vtest_create_resource2(UNUSED uint32_t length_dw)
825 {
826 struct vtest_context *ctx = vtest_get_current_context();
827 struct virgl_renderer_resource_create_args args;
828 size_t shm_size;
829 int ret;
830
831 ret = vtest_create_resource_decode_args2(ctx, &args, &shm_size);
832 if (ret < 0) {
833 return ret;
834 }
835
836 return vtest_create_resource_internal(ctx, &args, shm_size);
837 }
838
vtest_resource_unref(UNUSED uint32_t length_dw)839 int vtest_resource_unref(UNUSED uint32_t length_dw)
840 {
841 struct vtest_context *ctx = vtest_get_current_context();
842 uint32_t res_unref_buf[VCMD_RES_UNREF_SIZE];
843 int ret;
844 uint32_t handle;
845
846 ret = ctx->input->read(ctx->input, &res_unref_buf,
847 sizeof(res_unref_buf));
848 if (ret != sizeof(res_unref_buf)) {
849 return -1;
850 }
851
852 handle = res_unref_buf[VCMD_RES_UNREF_RES_HANDLE];
853 util_hash_table_remove(ctx->resource_table, intptr_to_pointer(handle));
854
855 return 0;
856 }
857
vtest_submit_cmd(uint32_t length_dw)858 int vtest_submit_cmd(uint32_t length_dw)
859 {
860 struct vtest_context *ctx = vtest_get_current_context();
861 uint32_t *cbuf;
862 int ret;
863
864 if (length_dw > renderer.max_length / 4) {
865 return -1;
866 }
867
868 cbuf = malloc(length_dw * 4);
869 if (!cbuf) {
870 return -1;
871 }
872
873 ret = ctx->input->read(ctx->input, cbuf, length_dw * 4);
874 if (ret != (int)length_dw * 4) {
875 free(cbuf);
876 return -1;
877 }
878
879 ret = virgl_renderer_submit_cmd(cbuf, ctx->ctx_id, length_dw);
880
881 free(cbuf);
882 return ret ? -1 : 0;
883 }
884
885 struct vtest_transfer_args {
886 uint32_t handle;
887 uint32_t level;
888 uint32_t stride;
889 uint32_t layer_stride;
890 struct virgl_box box;
891 uint32_t offset;
892 };
893
vtest_transfer_decode_args(struct vtest_context * ctx,struct vtest_transfer_args * args,uint32_t * data_size)894 static int vtest_transfer_decode_args(struct vtest_context *ctx,
895 struct vtest_transfer_args *args,
896 uint32_t *data_size)
897 {
898 uint32_t thdr_buf[VCMD_TRANSFER_HDR_SIZE];
899 int ret;
900
901 ret = ctx->input->read(ctx->input, thdr_buf, sizeof(thdr_buf));
902 if (ret != sizeof(thdr_buf)) {
903 return -1;
904 }
905
906 args->handle = thdr_buf[VCMD_TRANSFER_RES_HANDLE];
907 args->level = thdr_buf[VCMD_TRANSFER_LEVEL];
908 args->stride = thdr_buf[VCMD_TRANSFER_STRIDE];
909 args->layer_stride = thdr_buf[VCMD_TRANSFER_LAYER_STRIDE];
910 args->box.x = thdr_buf[VCMD_TRANSFER_X];
911 args->box.y = thdr_buf[VCMD_TRANSFER_Y];
912 args->box.z = thdr_buf[VCMD_TRANSFER_Z];
913 args->box.w = thdr_buf[VCMD_TRANSFER_WIDTH];
914 args->box.h = thdr_buf[VCMD_TRANSFER_HEIGHT];
915 args->box.d = thdr_buf[VCMD_TRANSFER_DEPTH];
916 args->offset = 0;
917
918 *data_size = thdr_buf[VCMD_TRANSFER_DATA_SIZE];
919
920 if (*data_size > renderer.max_length) {
921 return -ENOMEM;
922 }
923
924 return 0;
925 }
926
vtest_transfer_decode_args2(struct vtest_context * ctx,struct vtest_transfer_args * args)927 static int vtest_transfer_decode_args2(struct vtest_context *ctx,
928 struct vtest_transfer_args *args)
929 {
930 uint32_t thdr_buf[VCMD_TRANSFER2_HDR_SIZE];
931 int ret;
932
933 ret = ctx->input->read(ctx->input, thdr_buf, sizeof(thdr_buf));
934 if (ret != sizeof(thdr_buf)) {
935 return -1;
936 }
937
938 args->handle = thdr_buf[VCMD_TRANSFER2_RES_HANDLE];
939 args->level = thdr_buf[VCMD_TRANSFER2_LEVEL];
940 args->stride = 0;
941 args->layer_stride = 0;
942 args->box.x = thdr_buf[VCMD_TRANSFER2_X];
943 args->box.y = thdr_buf[VCMD_TRANSFER2_Y];
944 args->box.z = thdr_buf[VCMD_TRANSFER2_Z];
945 args->box.w = thdr_buf[VCMD_TRANSFER2_WIDTH];
946 args->box.h = thdr_buf[VCMD_TRANSFER2_HEIGHT];
947 args->box.d = thdr_buf[VCMD_TRANSFER2_DEPTH];
948 args->offset = thdr_buf[VCMD_TRANSFER2_OFFSET];
949
950 return 0;
951 }
952
vtest_transfer_get_internal(struct vtest_context * ctx,struct vtest_transfer_args * args,uint32_t data_size,bool do_transfer)953 static int vtest_transfer_get_internal(struct vtest_context *ctx,
954 struct vtest_transfer_args *args,
955 uint32_t data_size,
956 bool do_transfer)
957 {
958 struct vtest_resource *res;
959 struct iovec data_iov;
960 int ret = 0;
961
962 res = util_hash_table_get(ctx->resource_table,
963 intptr_to_pointer(args->handle));
964 if (!res) {
965 return report_failed_call("util_hash_table_get", -ESRCH);
966 }
967
968 if (data_size) {
969 data_iov.iov_len = data_size;
970 data_iov.iov_base = malloc(data_size);
971 if (!data_iov.iov_base) {
972 return -ENOMEM;
973 }
974 } else {
975 if (args->offset >= res->iov.iov_len) {
976 return report_failure("offset larger then length of backing store", -EFAULT);
977 }
978 }
979
980 if (do_transfer) {
981 ret = virgl_renderer_transfer_read_iov(res->res_id,
982 ctx->ctx_id,
983 args->level,
984 args->stride,
985 args->layer_stride,
986 &args->box,
987 args->offset,
988 data_size ? &data_iov : NULL,
989 data_size ? 1 : 0);
990 if (ret) {
991 report_failed_call("virgl_renderer_transfer_read_iov", ret);
992 }
993 } else if (data_size) {
994 memset(data_iov.iov_base, 0, data_iov.iov_len);
995 }
996
997 if (data_size) {
998 ret = vtest_block_write(ctx->out_fd, data_iov.iov_base, data_iov.iov_len);
999 if (ret > 0)
1000 ret = 0;
1001
1002 free(data_iov.iov_base);
1003 }
1004
1005 return ret;
1006 }
1007
vtest_transfer_put_internal(struct vtest_context * ctx,struct vtest_transfer_args * args,uint32_t data_size,bool do_transfer)1008 static int vtest_transfer_put_internal(struct vtest_context *ctx,
1009 struct vtest_transfer_args *args,
1010 uint32_t data_size,
1011 bool do_transfer)
1012 {
1013 struct vtest_resource *res;
1014 struct iovec data_iov;
1015 int ret = 0;
1016
1017 res = util_hash_table_get(ctx->resource_table,
1018 intptr_to_pointer(args->handle));
1019 if (!res) {
1020 return report_failed_call("util_hash_table_get", -ESRCH);
1021 }
1022
1023 if (data_size) {
1024 data_iov.iov_len = data_size;
1025 data_iov.iov_base = malloc(data_size);
1026 if (!data_iov.iov_base) {
1027 return -ENOMEM;
1028 }
1029
1030 ret = ctx->input->read(ctx->input, data_iov.iov_base, data_iov.iov_len);
1031 if (ret < 0) {
1032 return ret;
1033 }
1034 }
1035
1036 if (do_transfer) {
1037 ret = virgl_renderer_transfer_write_iov(res->res_id,
1038 ctx->ctx_id,
1039 args->level,
1040 args->stride,
1041 args->layer_stride,
1042 &args->box,
1043 args->offset,
1044 data_size ? &data_iov : NULL,
1045 data_size ? 1 : 0);
1046 if (ret) {
1047 report_failed_call("virgl_renderer_transfer_write_iov", ret);
1048 }
1049 }
1050
1051 if (data_size) {
1052 free(data_iov.iov_base);
1053 }
1054
1055 return ret;
1056 }
1057
vtest_transfer_get(UNUSED uint32_t length_dw)1058 int vtest_transfer_get(UNUSED uint32_t length_dw)
1059 {
1060 struct vtest_context *ctx = vtest_get_current_context();
1061 int ret;
1062 struct vtest_transfer_args args;
1063 uint32_t data_size;
1064
1065 ret = vtest_transfer_decode_args(ctx, &args, &data_size);
1066 if (ret < 0) {
1067 return ret;
1068 }
1069
1070 return vtest_transfer_get_internal(ctx, &args, data_size, true);
1071 }
1072
vtest_transfer_get_nop(UNUSED uint32_t length_dw)1073 int vtest_transfer_get_nop(UNUSED uint32_t length_dw)
1074 {
1075 struct vtest_context *ctx = vtest_get_current_context();
1076 int ret;
1077 struct vtest_transfer_args args;
1078 uint32_t data_size;
1079
1080 ret = vtest_transfer_decode_args(ctx, &args, &data_size);
1081 if (ret < 0) {
1082 return ret;
1083 }
1084
1085 return vtest_transfer_get_internal(ctx, &args, data_size, false);
1086 }
1087
vtest_transfer_put(UNUSED uint32_t length_dw)1088 int vtest_transfer_put(UNUSED uint32_t length_dw)
1089 {
1090 struct vtest_context *ctx = vtest_get_current_context();
1091 int ret;
1092 struct vtest_transfer_args args;
1093 uint32_t data_size;
1094
1095 ret = vtest_transfer_decode_args(ctx, &args, &data_size);
1096 if (ret < 0) {
1097 return ret;
1098 }
1099
1100 return vtest_transfer_put_internal(ctx, &args, data_size, true);
1101 }
1102
vtest_transfer_put_nop(UNUSED uint32_t length_dw)1103 int vtest_transfer_put_nop(UNUSED uint32_t length_dw)
1104 {
1105 struct vtest_context *ctx = vtest_get_current_context();
1106 int ret;
1107 struct vtest_transfer_args args;
1108 uint32_t data_size;
1109
1110 ret = vtest_transfer_decode_args(ctx, &args, &data_size);
1111 if (ret < 0) {
1112 return ret;
1113 }
1114
1115 return vtest_transfer_put_internal(ctx, &args, data_size, false);
1116 }
1117
vtest_transfer_get2(UNUSED uint32_t length_dw)1118 int vtest_transfer_get2(UNUSED uint32_t length_dw)
1119 {
1120 struct vtest_context *ctx = vtest_get_current_context();
1121 int ret;
1122 struct vtest_transfer_args args;
1123
1124 ret = vtest_transfer_decode_args2(ctx, &args);
1125 if (ret < 0) {
1126 return ret;
1127 }
1128
1129 return vtest_transfer_get_internal(ctx, &args, 0, true);
1130 }
1131
vtest_transfer_get2_nop(UNUSED uint32_t length_dw)1132 int vtest_transfer_get2_nop(UNUSED uint32_t length_dw)
1133 {
1134 struct vtest_context *ctx = vtest_get_current_context();
1135 int ret;
1136 struct vtest_transfer_args args;
1137
1138 ret = vtest_transfer_decode_args2(ctx, &args);
1139 if (ret < 0) {
1140 return ret;
1141 }
1142
1143 return vtest_transfer_get_internal(ctx, &args, 0, false);
1144 }
1145
vtest_transfer_put2(UNUSED uint32_t length_dw)1146 int vtest_transfer_put2(UNUSED uint32_t length_dw)
1147 {
1148 struct vtest_context *ctx = vtest_get_current_context();
1149 int ret;
1150 struct vtest_transfer_args args;
1151
1152 ret = vtest_transfer_decode_args2(ctx, &args);
1153 if (ret < 0) {
1154 return ret;
1155 }
1156
1157 return vtest_transfer_put_internal(ctx, &args, 0, true);
1158 }
1159
vtest_transfer_put2_nop(UNUSED uint32_t length_dw)1160 int vtest_transfer_put2_nop(UNUSED uint32_t length_dw)
1161 {
1162 struct vtest_context *ctx = vtest_get_current_context();
1163 int ret;
1164 struct vtest_transfer_args args;
1165
1166 ret = vtest_transfer_decode_args2(ctx, &args);
1167 if (ret < 0) {
1168 return ret;
1169 }
1170
1171 return vtest_transfer_put_internal(ctx, &args, 0, false);
1172 }
1173
vtest_resource_busy_wait(UNUSED uint32_t length_dw)1174 int vtest_resource_busy_wait(UNUSED uint32_t length_dw)
1175 {
1176 struct vtest_context *ctx = vtest_get_current_context();
1177 uint32_t bw_buf[VCMD_BUSY_WAIT_SIZE];
1178 int ret, fd;
1179 int flags;
1180 uint32_t hdr_buf[VTEST_HDR_SIZE];
1181 uint32_t reply_buf[1];
1182 bool busy = false;
1183
1184 ret = ctx->input->read(ctx->input, &bw_buf, sizeof(bw_buf));
1185 if (ret != sizeof(bw_buf)) {
1186 return -1;
1187 }
1188
1189 /* clients often send VCMD_PING_PROTOCOL_VERSION followed by
1190 * VCMD_RESOURCE_BUSY_WAIT with handle 0 to figure out if
1191 * VCMD_PING_PROTOCOL_VERSION is supported. We need to make a special case
1192 * for that.
1193 */
1194 if (!ctx->context_initialized && bw_buf[VCMD_BUSY_WAIT_HANDLE])
1195 return -1;
1196
1197 /* handle = bw_buf[VCMD_BUSY_WAIT_HANDLE]; unused as of now */
1198 flags = bw_buf[VCMD_BUSY_WAIT_FLAGS];
1199
1200 if (flags == VCMD_BUSY_WAIT_FLAG_WAIT) {
1201 do {
1202 if (renderer.last_fence == (renderer.fence_id - 1)) {
1203 break;
1204 }
1205
1206 fd = virgl_renderer_get_poll_fd();
1207 if (fd != -1) {
1208 vtest_wait_for_fd_read(fd);
1209 }
1210
1211 virgl_renderer_poll();
1212 } while (1);
1213
1214 busy = false;
1215 } else {
1216 busy = renderer.last_fence != (renderer.fence_id - 1);
1217 }
1218
1219 hdr_buf[VTEST_CMD_LEN] = 1;
1220 hdr_buf[VTEST_CMD_ID] = VCMD_RESOURCE_BUSY_WAIT;
1221 reply_buf[0] = busy ? 1 : 0;
1222
1223 ret = vtest_block_write(ctx->out_fd, hdr_buf, sizeof(hdr_buf));
1224 if (ret < 0) {
1225 return ret;
1226 }
1227
1228 ret = vtest_block_write(ctx->out_fd, reply_buf, sizeof(reply_buf));
1229 if (ret < 0) {
1230 return ret;
1231 }
1232
1233 return 0;
1234 }
1235
vtest_renderer_create_fence(void)1236 int vtest_renderer_create_fence(void)
1237 {
1238 struct vtest_context *ctx = vtest_get_current_context();
1239 virgl_renderer_create_fence(renderer.fence_id++, ctx->ctx_id);
1240 return 0;
1241 }
1242
vtest_poll(void)1243 int vtest_poll(void)
1244 {
1245 virgl_renderer_poll();
1246 return 0;
1247 }
1248
vtest_set_max_length(uint32_t length)1249 void vtest_set_max_length(uint32_t length)
1250 {
1251 renderer.max_length = length;
1252 }
1253