1 /*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Permission is hereby granted, free of charge, to any person
5 * obtaining a copy of this software and associated documentation
6 * files (the "Software"), to deal in the Software without
7 * restriction, including without limitation the rights to use, copy,
8 * modify, merge, publish, distribute, sublicense, and/or sell copies
9 * of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24
25 #include <arch/io-mem.h>
26 #include <assert.h>
27 #include <stdbool.h>
28 #include <stdint.h>
29 #include <test-runner-arch.h>
30 #include <trusty/sysdeps.h>
31 #include <virtio-device.h>
32 #include <virtio.h>
33
vq_init(struct virtq * vq,struct virtq_raw * raw,struct virtio_config * vio,bool is_input)34 void vq_init(struct virtq* vq,
35 struct virtq_raw* raw,
36 struct virtio_config* vio,
37 bool is_input) {
38 uint16_t flags = 0;
39
40 if (is_input) {
41 flags = VIRTQ_DESC_F_WRITE;
42 }
43
44 vq->raw = raw;
45 vq->num_bufs = VQ_SIZE;
46 for (size_t i = 0; i < vq->num_bufs; i++) {
47 vq->raw->desc[i].flags = flags;
48 }
49
50 vq->vio = vio;
51 }
52
vq_make_avail(struct virtq * vq,uint16_t desc_id)53 void vq_make_avail(struct virtq* vq, uint16_t desc_id) {
54 io_write_16(&vq->raw->avail.ring[vq->raw->avail.idx % vq->num_bufs],
55 desc_id);
56 io_write_16(&vq->raw->avail.idx, vq->raw->avail.idx + 1);
57 }
58
vq_wait(struct virtq * vq)59 void vq_wait(struct virtq* vq) {
60 while (!vq_ready(vq)) {
61 }
62 }
63
vq_adv(struct virtq * vq)64 uint32_t vq_adv(struct virtq* vq) {
65 return vq->raw->used.ring[vq->old_used_idx++ % vq->num_bufs].len;
66 }
67
vq_set_buf_w(struct virtq * vq,uint16_t desc_id,void * data,size_t len)68 void vq_set_buf_w(struct virtq* vq, uint16_t desc_id, void* data, size_t len) {
69 vq->raw->desc[desc_id].addr = (uint64_t)data;
70 vq->raw->desc[desc_id].len = len;
71 assert(vq->raw->desc[desc_id].flags == VIRTQ_DESC_F_WRITE);
72 }
73
vq_set_buf_r(struct virtq * vq,uint16_t desc_id,const void * data,size_t len)74 void vq_set_buf_r(struct virtq* vq,
75 uint16_t desc_id,
76 const void* data,
77 size_t len) {
78 vq->raw->desc[desc_id].addr = (uint64_t)data;
79 vq->raw->desc[desc_id].len = len;
80 assert(vq->raw->desc[desc_id].flags == 0);
81 }
82
send_vq(struct virtq * vq,const char * data,size_t len)83 ssize_t send_vq(struct virtq* vq, const char* data, size_t len) {
84 size_t idx = vq->old_used_idx;
85
86 if (len == 0) {
87 return 0;
88 }
89
90 vq_set_buf_r(vq, idx % vq->num_bufs, data, len);
91 vq_make_avail(vq, idx % vq->num_bufs);
92 vq_kick(vq);
93 vq_wait(vq);
94 vq_set_buf_r(vq, idx % vq->num_bufs, NULL, 0);
95 /*
96 * QEMU's device does not set len correctly, as per the legacy-mode
97 * notes. This means the value returned by vq_adv is unreliable, so we
98 * assume no partial write and return len.
99 */
100 vq_adv(vq);
101 return len;
102 }
103
recv_vq(struct virtq * vq,char * data,size_t len)104 ssize_t recv_vq(struct virtq* vq, char* data, size_t len) {
105 size_t idx = vq->old_used_idx;
106
107 if (len == 0) {
108 return 0;
109 }
110
111 vq_set_buf_w(vq, idx % vq->num_bufs, data, len);
112 vq_make_avail(vq, idx % vq->num_bufs);
113 vq_kick(vq);
114 vq_wait(vq);
115 vq_set_buf_w(vq, idx % vq->num_bufs, NULL, 0);
116 return vq_adv(vq);
117 }
118