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 #include <sys/stat.h>
39
40
41 #include "vtest.h"
42 #include "vtest_shm.h"
43 #include "vtest_protocol.h"
44
45 #include "util.h"
46 #include "util/u_debug.h"
47 #include "util/u_math.h"
48 #include "util/u_memory.h"
49 #include "util/u_hash_table.h"
50
51
52 static int ctx_id = 1;
53 static int fence_id = 1;
54 static uint32_t max_length = UINT_MAX;
55
56
57 struct vtest_renderer {
58 struct vtest_input *input;
59 int out_fd;
60 unsigned protocol_version;
61 struct util_hash_table *iovec_hash;
62 const char *rendernode_name;
63 };
64
65 static int last_fence;
vtest_write_fence(UNUSED void * cookie,uint32_t fence_id_in)66 static void vtest_write_fence(UNUSED void *cookie, uint32_t fence_id_in)
67 {
68 last_fence = fence_id_in;
69 }
70
71 static int last_fence;
vtest_get_drm_fd(void * cookie)72 static int vtest_get_drm_fd(void *cookie)
73 {
74 int fd = -1;
75 struct vtest_renderer *renderer = (struct vtest_renderer*)cookie;
76 if (!renderer->rendernode_name)
77 return -1;
78 fd = open(renderer->rendernode_name, O_RDWR | O_CLOEXEC | O_NOCTTY | O_NONBLOCK);
79 if (fd == -1)
80 fprintf(stderr, "Unable to open rendernode '%s' falling back to default search\n",
81 renderer->rendernode_name);
82 return fd;
83 }
84
85 struct virgl_renderer_callbacks vtest_cbs = {
86 .version = 2,
87 .write_fence = vtest_write_fence,
88 .get_drm_fd = vtest_get_drm_fd
89 };
90
91
92 struct vtest_renderer renderer;
93
94 static unsigned
hash_func(void * key)95 hash_func(void *key)
96 {
97 intptr_t ip = pointer_to_intptr(key);
98 return (unsigned)(ip & 0xffffffff);
99 }
100
101 static int
compare_iovecs(void * key1,void * key2)102 compare_iovecs(void *key1, void *key2)
103 {
104 if (key1 < key2) {
105 return -1;
106 } else if (key1 > key2) {
107 return 1;
108 } else {
109 return 0;
110 }
111 }
112
free_iovec(void * value)113 static void free_iovec(void *value)
114 {
115 struct iovec *iovec = value;
116 if (iovec->iov_base)
117 munmap(iovec->iov_base, iovec->iov_len);
118 free(iovec);
119 }
120
vtest_block_write(int fd,void * buf,int size)121 static int vtest_block_write(int fd, void *buf, int size)
122 {
123 char *ptr = buf;
124 int left;
125 int ret;
126 left = size;
127
128 do {
129 ret = write(fd, ptr, left);
130 if (ret < 0) {
131 return -errno;
132 }
133
134 left -= ret;
135 ptr += ret;
136 } while (left);
137
138 return size;
139 }
140
vtest_block_read(struct vtest_input * input,void * buf,int size)141 int vtest_block_read(struct vtest_input *input, void *buf, int size)
142 {
143 int fd = input->data.fd;
144 char *ptr = buf;
145 int left;
146 int ret;
147 static int savefd = -1;
148
149 left = size;
150 do {
151 ret = read(fd, ptr, left);
152 if (ret <= 0) {
153 return ret == -1 ? -errno : 0;
154 }
155
156 left -= ret;
157 ptr += ret;
158 } while (left);
159
160 if (getenv("VTEST_SAVE")) {
161 if (savefd == -1) {
162 savefd = open(getenv("VTEST_SAVE"),
163 O_CLOEXEC|O_CREAT|O_WRONLY|O_TRUNC|O_SYNC, S_IRUSR|S_IWUSR);
164 if (savefd == -1) {
165 perror("error opening save file");
166 exit(1);
167 }
168 }
169 if (write(savefd, buf, size) != size) {
170 perror("failed to save");
171 exit(1);
172 }
173 }
174
175 return size;
176 }
177
vtest_send_fd(int socket_fd,int fd)178 static int vtest_send_fd(int socket_fd, int fd)
179 {
180 struct iovec iovec;
181 char buf[CMSG_SPACE(sizeof(int))], c;
182 struct msghdr msgh = { 0 };
183 memset(buf, 0, sizeof(buf));
184
185 iovec.iov_base = &c;
186 iovec.iov_len = sizeof(char);
187
188 msgh.msg_name = NULL;
189 msgh.msg_namelen = 0;
190 msgh.msg_iov = &iovec;
191 msgh.msg_iovlen = 1;
192 msgh.msg_control = buf;
193 msgh.msg_controllen = sizeof(buf);
194 msgh.msg_flags = 0;
195
196 struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msgh);
197 cmsg->cmsg_level = SOL_SOCKET;
198 cmsg->cmsg_type = SCM_RIGHTS;
199 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
200
201 *((int *) CMSG_DATA(cmsg)) = fd;
202
203 int size = sendmsg(socket_fd, &msgh, 0);
204 if (size < 0) {
205 return report_failure("Failed to send fd", -EINVAL);
206 }
207
208 return 0;
209 }
210
vtest_buf_read(struct vtest_input * input,void * buf,int size)211 int vtest_buf_read(struct vtest_input *input, void *buf, int size)
212 {
213 struct vtest_buffer *inbuf = input->data.buffer;
214 if (size > inbuf->size) {
215 return 0;
216 }
217
218 memcpy(buf, inbuf->buffer, size);
219 inbuf->buffer += size;
220 inbuf->size -= size;
221
222 return size;
223 }
224
vtest_create_renderer(struct vtest_input * input,int out_fd,uint32_t length,int ctx_flags,const char * render_device)225 int vtest_create_renderer(struct vtest_input *input, int out_fd, uint32_t length,
226 int ctx_flags, const char * render_device)
227 {
228 char *vtestname;
229 int ret;
230
231 renderer.iovec_hash = util_hash_table_create(hash_func, compare_iovecs, free_iovec);
232 renderer.input = input;
233 renderer.out_fd = out_fd;
234 renderer.rendernode_name = render_device;
235
236 /* By default we support version 0 unless VCMD_PROTOCOL_VERSION is sent */
237 renderer.protocol_version = 0;
238
239 ret = virgl_renderer_init(&renderer,
240 ctx_flags | VIRGL_RENDERER_THREAD_SYNC, &vtest_cbs);
241 if (ret) {
242 fprintf(stderr, "failed to initialise renderer.\n");
243 return -1;
244 }
245
246 if (length > 1024 * 1024) {
247 return -1;
248 }
249
250 vtestname = calloc(1, length + 1);
251 if (!vtestname) {
252 return -1;
253 }
254
255 ret = renderer.input->read(renderer.input, vtestname, length);
256 if (ret != (int)length) {
257 ret = -1;
258 goto end;
259 }
260
261 ret = virgl_renderer_context_create(ctx_id, strlen(vtestname), vtestname);
262
263 end:
264 free(vtestname);
265 return ret;
266 }
267
vtest_ping_protocol_version(UNUSED uint32_t length_dw)268 int vtest_ping_protocol_version(UNUSED uint32_t length_dw)
269 {
270 uint32_t hdr_buf[VTEST_HDR_SIZE];
271 int ret;
272
273 hdr_buf[VTEST_CMD_LEN] = VCMD_PING_PROTOCOL_VERSION_SIZE;
274 hdr_buf[VTEST_CMD_ID] = VCMD_PING_PROTOCOL_VERSION;
275 ret = vtest_block_write(renderer.out_fd, hdr_buf, sizeof(hdr_buf));
276 if (ret < 0) {
277 return ret;
278 }
279
280 return 0;
281 }
282
vtest_protocol_version(UNUSED uint32_t length_dw)283 int vtest_protocol_version(UNUSED uint32_t length_dw)
284 {
285 uint32_t hdr_buf[VTEST_HDR_SIZE];
286 uint32_t version_buf[VCMD_PROTOCOL_VERSION_SIZE];
287 int ret;
288
289 ret = renderer.input->read(renderer.input, &version_buf, sizeof(version_buf));
290 if (ret != sizeof(version_buf))
291 return -1;
292
293 renderer.protocol_version = MIN2(version_buf[VCMD_PROTOCOL_VERSION_VERSION],
294 VTEST_PROTOCOL_VERSION);
295
296 /*
297 * We've deprecated protocol version 1. All of it's called sites are being
298 * moved protocol version 2. If the server supports version 2 and the guest
299 * supports verison 1, fall back to version 0.
300 */
301 if (renderer.protocol_version == 1) {
302 printf("Older guest Mesa detected, fallbacking to protocol version 0\n");
303 renderer.protocol_version = 0;
304 }
305
306 /* Protocol version 2 requires shm support. */
307 if (!vtest_shm_check()) {
308 printf("Shared memory not supported, fallbacking to protocol version 0\n");
309 renderer.protocol_version = 0;
310 }
311
312 hdr_buf[VTEST_CMD_LEN] = VCMD_PROTOCOL_VERSION_SIZE;
313 hdr_buf[VTEST_CMD_ID] = VCMD_PROTOCOL_VERSION;
314
315 version_buf[VCMD_PROTOCOL_VERSION_VERSION] = renderer.protocol_version;
316
317 ret = vtest_block_write(renderer.out_fd, hdr_buf, sizeof(hdr_buf));
318 if (ret < 0) {
319 return ret;
320 }
321
322 ret = vtest_block_write(renderer.out_fd, version_buf, sizeof(version_buf));
323 if (ret < 0) {
324 return ret;
325 }
326
327 return 0;
328 }
329
vtest_destroy_renderer(void)330 void vtest_destroy_renderer(void)
331 {
332 virgl_renderer_context_destroy(ctx_id);
333 virgl_renderer_cleanup(&renderer);
334 util_hash_table_destroy(renderer.iovec_hash);
335 renderer.iovec_hash = NULL;
336 renderer.input = NULL;
337 renderer.out_fd = -1;
338 }
339
vtest_send_caps2(UNUSED uint32_t length_dw)340 int vtest_send_caps2(UNUSED uint32_t length_dw)
341 {
342 uint32_t hdr_buf[2];
343 void *caps_buf;
344 int ret;
345 uint32_t max_ver, max_size;
346
347 virgl_renderer_get_cap_set(2, &max_ver, &max_size);
348
349 if (max_size == 0) {
350 return -1;
351 }
352
353 caps_buf = malloc(max_size);
354 if (!caps_buf) {
355 return -1;
356 }
357
358 virgl_renderer_fill_caps(2, 1, caps_buf);
359
360 hdr_buf[0] = max_size + 1;
361 hdr_buf[1] = 2;
362 ret = vtest_block_write(renderer.out_fd, hdr_buf, 8);
363 if (ret < 0) {
364 goto end;
365 }
366
367 vtest_block_write(renderer.out_fd, caps_buf, max_size);
368 if (ret < 0) {
369 goto end;
370 }
371
372 end:
373 free(caps_buf);
374 return 0;
375 }
376
vtest_send_caps(UNUSED uint32_t length_dw)377 int vtest_send_caps(UNUSED uint32_t length_dw)
378 {
379 uint32_t max_ver, max_size;
380 void *caps_buf;
381 uint32_t hdr_buf[2];
382 int ret;
383
384 virgl_renderer_get_cap_set(1, &max_ver, &max_size);
385
386 caps_buf = malloc(max_size);
387 if (!caps_buf) {
388 return -1;
389 }
390
391 virgl_renderer_fill_caps(1, 1, caps_buf);
392
393 hdr_buf[0] = max_size + 1;
394 hdr_buf[1] = 1;
395 ret = vtest_block_write(renderer.out_fd, hdr_buf, 8);
396 if (ret < 0) {
397 goto end;
398 }
399
400 vtest_block_write(renderer.out_fd, caps_buf, max_size);
401 if (ret < 0) {
402 goto end;
403 }
404
405 end:
406 free(caps_buf);
407 return 0;
408 }
409
vtest_create_resource(UNUSED uint32_t length_dw)410 int vtest_create_resource(UNUSED uint32_t length_dw)
411 {
412 uint32_t res_create_buf[VCMD_RES_CREATE_SIZE];
413 struct virgl_renderer_resource_create_args args;
414 int ret;
415
416 ret = renderer.input->read(renderer.input, &res_create_buf,
417 sizeof(res_create_buf));
418 if (ret != sizeof(res_create_buf)) {
419 return -1;
420 }
421
422 args.handle = res_create_buf[VCMD_RES_CREATE_RES_HANDLE];
423 args.target = res_create_buf[VCMD_RES_CREATE_TARGET];
424 args.format = res_create_buf[VCMD_RES_CREATE_FORMAT];
425 args.bind = res_create_buf[VCMD_RES_CREATE_BIND];
426
427 args.width = res_create_buf[VCMD_RES_CREATE_WIDTH];
428 args.height = res_create_buf[VCMD_RES_CREATE_HEIGHT];
429 args.depth = res_create_buf[VCMD_RES_CREATE_DEPTH];
430 args.array_size = res_create_buf[VCMD_RES_CREATE_ARRAY_SIZE];
431 args.last_level = res_create_buf[VCMD_RES_CREATE_LAST_LEVEL];
432 args.nr_samples = res_create_buf[VCMD_RES_CREATE_NR_SAMPLES];
433 args.flags = 0;
434
435 ret = virgl_renderer_resource_create(&args, NULL, 0);
436
437 virgl_renderer_ctx_attach_resource(ctx_id, args.handle);
438 return ret;
439 }
440
vtest_create_resource2(UNUSED uint32_t length_dw)441 int vtest_create_resource2(UNUSED uint32_t length_dw)
442 {
443 uint32_t res_create_buf[VCMD_RES_CREATE2_SIZE];
444 struct virgl_renderer_resource_create_args args;
445 struct iovec *iovec;
446 int ret, fd;
447
448 ret = renderer.input->read(renderer.input, &res_create_buf,
449 sizeof(res_create_buf));
450 if (ret != sizeof(res_create_buf)) {
451 return -1;
452 }
453
454 args.handle = res_create_buf[VCMD_RES_CREATE2_RES_HANDLE];
455 args.target = res_create_buf[VCMD_RES_CREATE2_TARGET];
456 args.format = res_create_buf[VCMD_RES_CREATE2_FORMAT];
457 args.bind = res_create_buf[VCMD_RES_CREATE2_BIND];
458
459 args.width = res_create_buf[VCMD_RES_CREATE2_WIDTH];
460 args.height = res_create_buf[VCMD_RES_CREATE2_HEIGHT];
461 args.depth = res_create_buf[VCMD_RES_CREATE2_DEPTH];
462 args.array_size = res_create_buf[VCMD_RES_CREATE2_ARRAY_SIZE];
463 args.last_level = res_create_buf[VCMD_RES_CREATE2_LAST_LEVEL];
464 args.nr_samples = res_create_buf[VCMD_RES_CREATE2_NR_SAMPLES];
465 args.flags = 0;
466
467 // Check that the handle doesn't already exist.
468 if (util_hash_table_get(renderer.iovec_hash, intptr_to_pointer(args.handle))) {
469 return -EEXIST;
470 }
471
472 ret = virgl_renderer_resource_create(&args, NULL, 0);
473 if (ret)
474 return report_failed_call("virgl_renderer_resource_create", ret);
475
476 virgl_renderer_ctx_attach_resource(ctx_id, args.handle);
477
478 iovec = CALLOC_STRUCT(iovec);
479 if (!iovec) {
480 return -ENOMEM;
481 }
482
483 iovec->iov_len = res_create_buf[VCMD_RES_CREATE2_DATA_SIZE];
484
485 /* Multi-sample textures have no backing store, but an associated GL resource. */
486 if (iovec->iov_len == 0) {
487 iovec->iov_base = NULL;
488 goto out;
489 }
490
491 fd = vtest_new_shm(args.handle, iovec->iov_len);
492 if (fd < 0) {
493 FREE(iovec);
494 return report_failed_call("vtest_new_shm", fd);
495 }
496
497 iovec->iov_base = mmap(NULL, iovec->iov_len, PROT_WRITE | PROT_READ,
498 MAP_SHARED, fd, 0);
499
500 if (iovec->iov_base == MAP_FAILED) {
501 close(fd);
502 FREE(iovec);
503 return -ENOMEM;
504 }
505
506 ret = vtest_send_fd(renderer.out_fd, fd);
507 if (ret < 0) {
508 close(fd);
509 munmap(iovec->iov_base, iovec->iov_len);
510 return report_failed_call("vtest_send_fd", ret);
511 }
512
513 /* Closing the file descriptor does not unmap the region. */
514 close(fd);
515
516 out:
517 virgl_renderer_resource_attach_iov(args.handle, iovec, 1);
518 util_hash_table_set(renderer.iovec_hash, intptr_to_pointer(args.handle), iovec);
519 return 0;
520 }
521
vtest_resource_unref(UNUSED uint32_t length_dw)522 int vtest_resource_unref(UNUSED uint32_t length_dw)
523 {
524 uint32_t res_unref_buf[VCMD_RES_UNREF_SIZE];
525 int ret;
526 uint32_t handle;
527
528 ret = renderer.input->read(renderer.input, &res_unref_buf,
529 sizeof(res_unref_buf));
530 if (ret != sizeof(res_unref_buf)) {
531 return -1;
532 }
533
534 handle = res_unref_buf[VCMD_RES_UNREF_RES_HANDLE];
535 virgl_renderer_ctx_attach_resource(ctx_id, handle);
536
537 virgl_renderer_resource_detach_iov(handle, NULL, NULL);
538 util_hash_table_remove(renderer.iovec_hash, intptr_to_pointer(handle));
539
540 virgl_renderer_resource_unref(handle);
541 return 0;
542 }
543
vtest_submit_cmd(uint32_t length_dw)544 int vtest_submit_cmd(uint32_t length_dw)
545 {
546 uint32_t *cbuf;
547 int ret;
548
549 if (length_dw > max_length / 4) {
550 return -1;
551 }
552
553 cbuf = malloc(length_dw * 4);
554 if (!cbuf) {
555 return -1;
556 }
557
558 ret = renderer.input->read(renderer.input, cbuf, length_dw * 4);
559 if (ret != (int)length_dw * 4) {
560 free(cbuf);
561 return -1;
562 }
563
564 virgl_renderer_submit_cmd(cbuf, ctx_id, length_dw);
565
566 free(cbuf);
567 return 0;
568 }
569
570 #define DECODE_TRANSFER \
571 do { \
572 handle = thdr_buf[VCMD_TRANSFER_RES_HANDLE]; \
573 level = thdr_buf[VCMD_TRANSFER_LEVEL]; \
574 stride = thdr_buf[VCMD_TRANSFER_STRIDE]; \
575 layer_stride = thdr_buf[VCMD_TRANSFER_LAYER_STRIDE]; \
576 box.x = thdr_buf[VCMD_TRANSFER_X]; \
577 box.y = thdr_buf[VCMD_TRANSFER_Y]; \
578 box.z = thdr_buf[VCMD_TRANSFER_Z]; \
579 box.w = thdr_buf[VCMD_TRANSFER_WIDTH]; \
580 box.h = thdr_buf[VCMD_TRANSFER_HEIGHT]; \
581 box.d = thdr_buf[VCMD_TRANSFER_DEPTH]; \
582 data_size = thdr_buf[VCMD_TRANSFER_DATA_SIZE]; \
583 } while(0)
584
585
vtest_transfer_get(UNUSED uint32_t length_dw)586 int vtest_transfer_get(UNUSED uint32_t length_dw)
587 {
588 uint32_t thdr_buf[VCMD_TRANSFER_HDR_SIZE];
589 int ret;
590 int level;
591 uint32_t stride, layer_stride, handle;
592 struct virgl_box box;
593 uint32_t data_size;
594 void *ptr;
595 struct iovec iovec;
596
597 ret = renderer.input->read(renderer.input, thdr_buf,
598 VCMD_TRANSFER_HDR_SIZE * 4);
599 if (ret != VCMD_TRANSFER_HDR_SIZE * 4) {
600 return ret;
601 }
602
603 DECODE_TRANSFER;
604
605 if (data_size > max_length) {
606 return -ENOMEM;
607 }
608
609 ptr = malloc(data_size);
610 if (!ptr) {
611 return -ENOMEM;
612 }
613
614 iovec.iov_len = data_size;
615 iovec.iov_base = ptr;
616 ret = virgl_renderer_transfer_read_iov(handle,
617 ctx_id,
618 level,
619 stride,
620 layer_stride,
621 &box,
622 0,
623 &iovec, 1);
624 if (ret) {
625 fprintf(stderr," transfer read failed %d\n", ret);
626 }
627
628 ret = vtest_block_write(renderer.out_fd, ptr, data_size);
629
630 free(ptr);
631 return ret < 0 ? ret : 0;
632 }
633
vtest_transfer_get_nop(UNUSED uint32_t length_dw)634 int vtest_transfer_get_nop(UNUSED uint32_t length_dw)
635 {
636 uint32_t thdr_buf[VCMD_TRANSFER_HDR_SIZE];
637 int ret;
638 UNUSED int level;
639 UNUSED uint32_t stride, layer_stride, handle;
640 UNUSED struct virgl_box box;
641 uint32_t data_size;
642 void *ptr;
643
644 ret = renderer.input->read(renderer.input, thdr_buf,
645 VCMD_TRANSFER_HDR_SIZE * 4);
646 if (ret != VCMD_TRANSFER_HDR_SIZE * 4) {
647 return ret;
648 }
649
650 DECODE_TRANSFER;
651
652 if (data_size > max_length) {
653 return -ENOMEM;
654 }
655
656 ptr = malloc(data_size);
657 if (!ptr) {
658 return -ENOMEM;
659 }
660
661 memset(ptr, 0, data_size);
662
663 ret = vtest_block_write(renderer.out_fd, ptr, data_size);
664
665 free(ptr);
666 return ret < 0 ? ret : 0;
667 }
668
vtest_transfer_put(UNUSED uint32_t length_dw)669 int vtest_transfer_put(UNUSED uint32_t length_dw)
670 {
671 uint32_t thdr_buf[VCMD_TRANSFER_HDR_SIZE];
672 int ret;
673 int level;
674 uint32_t stride, layer_stride, handle;
675 struct virgl_box box;
676 uint32_t data_size;
677 void *ptr;
678 struct iovec iovec;
679
680 ret = renderer.input->read(renderer.input, thdr_buf,
681 VCMD_TRANSFER_HDR_SIZE * 4);
682 if (ret != VCMD_TRANSFER_HDR_SIZE * 4) {
683 return ret;
684 }
685
686 DECODE_TRANSFER;
687
688 if (data_size > max_length) {
689 return -ENOMEM;
690 }
691
692 ptr = malloc(data_size);
693 if (!ptr) {
694 return -ENOMEM;
695 }
696
697 ret = renderer.input->read(renderer.input, ptr, data_size);
698 if (ret < 0) {
699 return ret;
700 }
701
702 iovec.iov_len = data_size;
703 iovec.iov_base = ptr;
704 ret = virgl_renderer_transfer_write_iov(handle,
705 ctx_id,
706 level,
707 stride,
708 layer_stride,
709 &box,
710 0,
711 &iovec, 1);
712 if (ret) {
713 fprintf(stderr," transfer write failed %d\n", ret);
714 }
715
716 free(ptr);
717 return 0;
718 }
719
vtest_transfer_put_nop(UNUSED uint32_t length_dw)720 int vtest_transfer_put_nop(UNUSED uint32_t length_dw)
721 {
722 uint32_t thdr_buf[VCMD_TRANSFER_HDR_SIZE];
723 int ret;
724 UNUSED int level;
725 UNUSED uint32_t stride, layer_stride, handle;
726 UNUSED struct virgl_box box;
727 uint32_t data_size;
728 void *ptr;
729
730 ret = renderer.input->read(renderer.input, thdr_buf,
731 VCMD_TRANSFER_HDR_SIZE * 4);
732 if (ret != VCMD_TRANSFER_HDR_SIZE * 4) {
733 return ret;
734 }
735
736 DECODE_TRANSFER;
737
738 if (data_size > max_length) {
739 return -ENOMEM;
740 }
741
742 ptr = malloc(data_size);
743 if (!ptr) {
744 return -ENOMEM;
745 }
746
747 ret = renderer.input->read(renderer.input, ptr, data_size);
748 if (ret < 0) {
749 return ret;
750 }
751
752 free(ptr);
753 return 0;
754 }
755
756
757 #define DECODE_TRANSFER2 \
758 do { \
759 handle = thdr_buf[VCMD_TRANSFER2_RES_HANDLE]; \
760 level = thdr_buf[VCMD_TRANSFER2_LEVEL]; \
761 box.x = thdr_buf[VCMD_TRANSFER2_X]; \
762 box.y = thdr_buf[VCMD_TRANSFER2_Y]; \
763 box.z = thdr_buf[VCMD_TRANSFER2_Z]; \
764 box.w = thdr_buf[VCMD_TRANSFER2_WIDTH]; \
765 box.h = thdr_buf[VCMD_TRANSFER2_HEIGHT]; \
766 box.d = thdr_buf[VCMD_TRANSFER2_DEPTH]; \
767 offset = thdr_buf[VCMD_TRANSFER2_OFFSET]; \
768 } while(0)
769
770
vtest_transfer_get2(UNUSED uint32_t length_dw)771 int vtest_transfer_get2(UNUSED uint32_t length_dw)
772 {
773 uint32_t thdr_buf[VCMD_TRANSFER2_HDR_SIZE];
774 int ret;
775 int level;
776 uint32_t handle;
777 struct virgl_box box;
778 uint32_t offset;
779 struct iovec *iovec;
780
781 ret = renderer.input->read(renderer.input, thdr_buf, sizeof(thdr_buf));
782 if (ret != sizeof(thdr_buf)) {
783 return ret;
784 }
785
786 DECODE_TRANSFER2;
787
788 iovec = util_hash_table_get(renderer.iovec_hash, intptr_to_pointer(handle));
789 if (!iovec) {
790 return report_failed_call("util_hash_table_get", -ESRCH);
791 }
792
793 if (offset >= iovec->iov_len) {
794 return report_failure("offset larger then length of backing store", -EFAULT);
795 }
796
797 ret = virgl_renderer_transfer_read_iov(handle,
798 ctx_id,
799 level,
800 0,
801 0,
802 &box,
803 offset,
804 NULL, 0);
805 if (ret) {
806 return report_failed_call("virgl_renderer_transfer_read_iov", ret);
807 }
808
809 return 0;
810 }
811
vtest_transfer_get2_nop(UNUSED uint32_t length_dw)812 int vtest_transfer_get2_nop(UNUSED uint32_t length_dw)
813 {
814 uint32_t thdr_buf[VCMD_TRANSFER2_HDR_SIZE];
815 int ret;
816 UNUSED int level;
817 uint32_t handle;
818 UNUSED struct virgl_box box;
819 uint32_t offset;
820 struct iovec *iovec;
821
822 ret = renderer.input->read(renderer.input, thdr_buf, sizeof(thdr_buf));
823 if (ret != sizeof(thdr_buf)) {
824 return ret;
825 }
826
827 DECODE_TRANSFER2;
828
829 iovec = util_hash_table_get(renderer.iovec_hash, intptr_to_pointer(handle));
830 if (!iovec) {
831 return report_failed_call("util_hash_table_get", -ESRCH);
832 }
833
834 if (offset >= iovec->iov_len) {
835 return report_failure("offset larger then length of backing store", -EFAULT);
836 }
837
838 return 0;
839 }
840
vtest_transfer_put2(UNUSED uint32_t length_dw)841 int vtest_transfer_put2(UNUSED uint32_t length_dw)
842 {
843 uint32_t thdr_buf[VCMD_TRANSFER2_HDR_SIZE];
844 int ret;
845 int level;
846 uint32_t handle;
847 struct virgl_box box;
848 UNUSED uint32_t data_size;
849 uint32_t offset;
850 struct iovec *iovec;
851
852 ret = renderer.input->read(renderer.input, thdr_buf, sizeof(thdr_buf));
853 if (ret != sizeof(thdr_buf)) {
854 return ret;
855 }
856
857 DECODE_TRANSFER2;
858
859 iovec = util_hash_table_get(renderer.iovec_hash, intptr_to_pointer(handle));
860 if (!iovec) {
861 return report_failed_call("util_hash_table_get", -ESRCH);
862 }
863
864 ret = virgl_renderer_transfer_write_iov(handle,
865 ctx_id,
866 level,
867 0,
868 0,
869 &box,
870 offset,
871 NULL, 0);
872 if (ret) {
873 return report_failed_call("virgl_renderer_transfer_write_iov", ret);
874 }
875
876 return 0;
877 }
878
vtest_transfer_put2_nop(UNUSED uint32_t length_dw)879 int vtest_transfer_put2_nop(UNUSED uint32_t length_dw)
880 {
881 uint32_t thdr_buf[VCMD_TRANSFER2_HDR_SIZE];
882 int ret;
883 UNUSED int level;
884 uint32_t handle;
885 UNUSED struct virgl_box box;
886 UNUSED uint32_t data_size;
887 UNUSED uint32_t offset;
888 struct iovec *iovec;
889
890 ret = renderer.input->read(renderer.input, thdr_buf, sizeof(thdr_buf));
891 if (ret != sizeof(thdr_buf)) {
892 return ret;
893 }
894
895 DECODE_TRANSFER2;
896
897 iovec = util_hash_table_get(renderer.iovec_hash, intptr_to_pointer(handle));
898 if (!iovec) {
899 return report_failed_call("util_hash_table_get", -ESRCH);
900 }
901
902 return 0;
903 }
904
vtest_resource_busy_wait(UNUSED uint32_t length_dw)905 int vtest_resource_busy_wait(UNUSED uint32_t length_dw)
906 {
907 uint32_t bw_buf[VCMD_BUSY_WAIT_SIZE];
908 int ret, fd;
909 int flags;
910 uint32_t hdr_buf[VTEST_HDR_SIZE];
911 uint32_t reply_buf[1];
912 bool busy = false;
913
914 ret = renderer.input->read(renderer.input, &bw_buf, sizeof(bw_buf));
915 if (ret != sizeof(bw_buf)) {
916 return -1;
917 }
918
919 /* handle = bw_buf[VCMD_BUSY_WAIT_HANDLE]; unused as of now */
920 flags = bw_buf[VCMD_BUSY_WAIT_FLAGS];
921
922 if (flags == VCMD_BUSY_WAIT_FLAG_WAIT) {
923 do {
924 if (last_fence == (fence_id - 1)) {
925 break;
926 }
927
928 fd = virgl_renderer_get_poll_fd();
929 if (fd != -1) {
930 vtest_wait_for_fd_read(fd);
931 }
932
933 virgl_renderer_poll();
934 } while (1);
935
936 busy = false;
937 } else {
938 busy = last_fence != (fence_id - 1);
939 }
940
941 hdr_buf[VTEST_CMD_LEN] = 1;
942 hdr_buf[VTEST_CMD_ID] = VCMD_RESOURCE_BUSY_WAIT;
943 reply_buf[0] = busy ? 1 : 0;
944
945 ret = vtest_block_write(renderer.out_fd, hdr_buf, sizeof(hdr_buf));
946 if (ret < 0) {
947 return ret;
948 }
949
950 ret = vtest_block_write(renderer.out_fd, reply_buf, sizeof(reply_buf));
951 if (ret < 0) {
952 return ret;
953 }
954
955 return 0;
956 }
957
vtest_renderer_create_fence(void)958 int vtest_renderer_create_fence(void)
959 {
960 virgl_renderer_create_fence(fence_id++, ctx_id);
961 return 0;
962 }
963
vtest_poll(void)964 int vtest_poll(void)
965 {
966 virgl_renderer_poll();
967 return 0;
968 }
969
vtest_set_max_length(uint32_t length)970 void vtest_set_max_length(uint32_t length)
971 {
972 max_length = length;
973 }
974