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