1
2
3
4
5
6
7
8
9
10
11
12
13
14#include "qemu/osdep.h"
15#include "libqtest-single.h"
16#include "qemu/module.h"
17#include "libqos/qgraph.h"
18#include "libqos/virtio-iommu.h"
19#include "hw/virtio/virtio-iommu.h"
20
21#define PCI_SLOT_HP 0x06
22#define QVIRTIO_IOMMU_TIMEOUT_US (30 * 1000 * 1000)
23
24static QGuestAllocator *alloc;
25
26static void pci_config(void *obj, void *data, QGuestAllocator *t_alloc)
27{
28 QVirtioIOMMU *v_iommu = obj;
29 QVirtioDevice *dev = v_iommu->vdev;
30 uint64_t input_range_start = qvirtio_config_readq(dev, 8);
31 uint64_t input_range_end = qvirtio_config_readq(dev, 16);
32 uint32_t domain_range_start = qvirtio_config_readl(dev, 24);
33 uint32_t domain_range_end = qvirtio_config_readl(dev, 28);
34 uint8_t bypass = qvirtio_config_readb(dev, 36);
35
36 g_assert_cmpint(input_range_start, ==, 0);
37 g_assert_cmphex(input_range_end, ==, UINT64_MAX);
38 g_assert_cmpint(domain_range_start, ==, 0);
39 g_assert_cmpint(domain_range_end, ==, UINT32_MAX);
40 g_assert_cmpint(bypass, ==, 1);
41}
42
43static int read_tail_status(struct virtio_iommu_req_tail *buffer)
44{
45 int i;
46
47 for (i = 0; i < 3; i++) {
48 g_assert_cmpint(buffer->reserved[i], ==, 0);
49 }
50 return buffer->status;
51}
52
53
54
55
56
57
58
59static int send_attach_detach(QTestState *qts, QVirtioIOMMU *v_iommu,
60 uint8_t type, uint32_t domain, uint32_t ep)
61{
62 QVirtioDevice *dev = v_iommu->vdev;
63 QVirtQueue *vq = v_iommu->vq;
64 uint64_t ro_addr, wr_addr;
65 uint32_t free_head;
66 struct virtio_iommu_req_attach req = {};
67 size_t ro_size = sizeof(req) - sizeof(struct virtio_iommu_req_tail);
68 size_t wr_size = sizeof(struct virtio_iommu_req_tail);
69 struct virtio_iommu_req_tail buffer;
70 int ret;
71
72 req.head.type = type;
73 req.domain = cpu_to_le32(domain);
74 req.endpoint = cpu_to_le32(ep);
75
76 ro_addr = guest_alloc(alloc, ro_size);
77 wr_addr = guest_alloc(alloc, wr_size);
78
79 qtest_memwrite(qts, ro_addr, &req, ro_size);
80 free_head = qvirtqueue_add(qts, vq, ro_addr, ro_size, false, true);
81 qvirtqueue_add(qts, vq, wr_addr, wr_size, true, false);
82 qvirtqueue_kick(qts, dev, vq, free_head);
83 qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
84 QVIRTIO_IOMMU_TIMEOUT_US);
85 qtest_memread(qts, wr_addr, &buffer, wr_size);
86 ret = read_tail_status(&buffer);
87 guest_free(alloc, ro_addr);
88 guest_free(alloc, wr_addr);
89 return ret;
90}
91
92
93
94
95
96
97
98
99
100static int send_map(QTestState *qts, QVirtioIOMMU *v_iommu,
101 uint32_t domain, uint64_t virt_start, uint64_t virt_end,
102 uint64_t phys_start, uint32_t flags)
103{
104 QVirtioDevice *dev = v_iommu->vdev;
105 QVirtQueue *vq = v_iommu->vq;
106 uint64_t ro_addr, wr_addr;
107 uint32_t free_head;
108 struct virtio_iommu_req_map req;
109 size_t ro_size = sizeof(req) - sizeof(struct virtio_iommu_req_tail);
110 size_t wr_size = sizeof(struct virtio_iommu_req_tail);
111 struct virtio_iommu_req_tail buffer;
112 int ret;
113
114 req.head.type = VIRTIO_IOMMU_T_MAP;
115 req.domain = cpu_to_le32(domain);
116 req.virt_start = cpu_to_le64(virt_start);
117 req.virt_end = cpu_to_le64(virt_end);
118 req.phys_start = cpu_to_le64(phys_start);
119 req.flags = cpu_to_le32(flags);
120
121 ro_addr = guest_alloc(alloc, ro_size);
122 wr_addr = guest_alloc(alloc, wr_size);
123
124 qtest_memwrite(qts, ro_addr, &req, ro_size);
125 free_head = qvirtqueue_add(qts, vq, ro_addr, ro_size, false, true);
126 qvirtqueue_add(qts, vq, wr_addr, wr_size, true, false);
127 qvirtqueue_kick(qts, dev, vq, free_head);
128 qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
129 QVIRTIO_IOMMU_TIMEOUT_US);
130 qtest_memread(qts, wr_addr, &buffer, wr_size);
131 ret = read_tail_status(&buffer);
132 guest_free(alloc, ro_addr);
133 guest_free(alloc, wr_addr);
134 return ret;
135}
136
137
138
139
140
141
142
143static int send_unmap(QTestState *qts, QVirtioIOMMU *v_iommu,
144 uint32_t domain, uint64_t virt_start, uint64_t virt_end)
145{
146 QVirtioDevice *dev = v_iommu->vdev;
147 QVirtQueue *vq = v_iommu->vq;
148 uint64_t ro_addr, wr_addr;
149 uint32_t free_head;
150 struct virtio_iommu_req_unmap req;
151 size_t ro_size = sizeof(req) - sizeof(struct virtio_iommu_req_tail);
152 size_t wr_size = sizeof(struct virtio_iommu_req_tail);
153 struct virtio_iommu_req_tail buffer;
154 int ret;
155
156 req.head.type = VIRTIO_IOMMU_T_UNMAP;
157 req.domain = cpu_to_le32(domain);
158 req.virt_start = cpu_to_le64(virt_start);
159 req.virt_end = cpu_to_le64(virt_end);
160
161 ro_addr = guest_alloc(alloc, ro_size);
162 wr_addr = guest_alloc(alloc, wr_size);
163
164 qtest_memwrite(qts, ro_addr, &req, ro_size);
165 free_head = qvirtqueue_add(qts, vq, ro_addr, ro_size, false, true);
166 qvirtqueue_add(qts, vq, wr_addr, wr_size, true, false);
167 qvirtqueue_kick(qts, dev, vq, free_head);
168 qvirtio_wait_used_elem(qts, dev, vq, free_head, NULL,
169 QVIRTIO_IOMMU_TIMEOUT_US);
170 qtest_memread(qts, wr_addr, &buffer, wr_size);
171 ret = read_tail_status(&buffer);
172 guest_free(alloc, ro_addr);
173 guest_free(alloc, wr_addr);
174 return ret;
175}
176
177static void test_attach_detach(void *obj, void *data, QGuestAllocator *t_alloc)
178{
179 QVirtioIOMMU *v_iommu = obj;
180 QTestState *qts = global_qtest;
181 int ret;
182
183 alloc = t_alloc;
184
185
186
187
188 ret = send_attach_detach(qts, v_iommu, VIRTIO_IOMMU_T_ATTACH, 0, 0);
189 g_assert_cmpint(ret, ==, 0);
190
191
192 ret = send_attach_detach(qts, v_iommu, VIRTIO_IOMMU_T_ATTACH, 0, 444);
193 g_assert_cmpint(ret, ==, VIRTIO_IOMMU_S_NOENT);
194
195
196 ret = send_attach_detach(qts, v_iommu, VIRTIO_IOMMU_T_DETACH, 0, 1);
197 g_assert_cmpint(ret, ==, VIRTIO_IOMMU_S_NOENT);
198
199
200 ret = send_attach_detach(qts, v_iommu, VIRTIO_IOMMU_T_ATTACH, 1, 0);
201 g_assert_cmpint(ret, ==, 0);
202
203
204 ret = send_attach_detach(qts, v_iommu, VIRTIO_IOMMU_T_DETACH, 0, 0);
205 g_assert_cmpint(ret, ==, VIRTIO_IOMMU_S_INVAL);
206
207
208 ret = send_attach_detach(qts, v_iommu, VIRTIO_IOMMU_T_DETACH, 1, 0);
209 g_assert_cmpint(ret, ==, 0);
210
211 ret = send_attach_detach(qts, v_iommu, VIRTIO_IOMMU_T_ATTACH, 1, 0);
212 g_assert_cmpint(ret, ==, 0);
213 ret = send_map(qts, v_iommu, 1, 0x0, 0xFFF, 0xa1000,
214 VIRTIO_IOMMU_MAP_F_READ);
215 g_assert_cmpint(ret, ==, 0);
216 ret = send_map(qts, v_iommu, 1, 0x2000, 0x2FFF, 0xb1000,
217 VIRTIO_IOMMU_MAP_F_READ);
218 g_assert_cmpint(ret, ==, 0);
219 ret = send_attach_detach(qts, v_iommu, VIRTIO_IOMMU_T_DETACH, 1, 0);
220 g_assert_cmpint(ret, ==, 0);
221}
222
223
224static void test_map_unmap(void *obj, void *data, QGuestAllocator *t_alloc)
225{
226 QVirtioIOMMU *v_iommu = obj;
227 QTestState *qts = global_qtest;
228 int ret;
229
230 alloc = t_alloc;
231
232
233 ret = send_attach_detach(qts, v_iommu, VIRTIO_IOMMU_T_ATTACH, 1, 0);
234 g_assert_cmpint(ret, ==, 0);
235
236 ret = send_map(qts, v_iommu, 0, 0, 0xFFF, 0xa1000, VIRTIO_IOMMU_MAP_F_READ);
237 g_assert_cmpint(ret, ==, VIRTIO_IOMMU_S_NOENT);
238
239
240 ret = send_map(qts, v_iommu, 1, 0x0, 0xFFF, 0xa1000, VIRTIO_IOMMU_MAP_F_READ);
241 g_assert_cmpint(ret, ==, 0);
242
243
244 ret = send_map(qts, v_iommu, 1, 0, 0xFFFF, 0xb1000, VIRTIO_IOMMU_MAP_F_READ);
245 g_assert_cmpint(ret, ==, VIRTIO_IOMMU_S_INVAL);
246
247 ret = send_unmap(qts, v_iommu, 4, 0x10, 0xFFF);
248 g_assert_cmpint(ret, ==, VIRTIO_IOMMU_S_NOENT);
249
250 ret = send_unmap(qts, v_iommu, 1, 0x10, 0xFFF);
251 g_assert_cmpint(ret, ==, VIRTIO_IOMMU_S_RANGE);
252
253 ret = send_unmap(qts, v_iommu, 1, 0, 0x1000);
254 g_assert_cmpint(ret, ==, 0);
255
256
257
258
259 ret = send_unmap(qts, v_iommu, 1, 0, 4);
260 g_assert_cmpint(ret, ==, 0);
261
262
263 ret = send_map(qts, v_iommu, 1, 0, 9, 0xa1000, VIRTIO_IOMMU_MAP_F_READ);
264 g_assert_cmpint(ret, ==, 0);
265 ret = send_unmap(qts, v_iommu, 1, 0, 9);
266 g_assert_cmpint(ret, ==, 0);
267
268
269 ret = send_map(qts, v_iommu, 1, 0, 4, 0xb1000, VIRTIO_IOMMU_MAP_F_READ);
270 g_assert_cmpint(ret, ==, 0);
271 ret = send_map(qts, v_iommu, 1, 5, 9, 0xb2000, VIRTIO_IOMMU_MAP_F_READ);
272 g_assert_cmpint(ret, ==, 0);
273 ret = send_unmap(qts, v_iommu, 1, 0, 9);
274 g_assert_cmpint(ret, ==, 0);
275
276
277 ret = send_map(qts, v_iommu, 1, 0, 9, 0xc1000, VIRTIO_IOMMU_MAP_F_READ);
278 g_assert_cmpint(ret, ==, 0);
279
280 ret = send_unmap(qts, v_iommu, 1, 0, 4);
281 g_assert_cmpint(ret, ==, VIRTIO_IOMMU_S_RANGE);
282
283 ret = send_unmap(qts, v_iommu, 1, 0, 10);
284 g_assert_cmpint(ret, ==, 0);
285
286
287 ret = send_map(qts, v_iommu, 1, 0, 4, 0xd1000, VIRTIO_IOMMU_MAP_F_READ);
288 g_assert_cmpint(ret, ==, 0);
289 ret = send_map(qts, v_iommu, 1, 5, 9, 0xd2000, VIRTIO_IOMMU_MAP_F_READ);
290 g_assert_cmpint(ret, ==, 0);
291 ret = send_unmap(qts, v_iommu, 1, 0, 4);
292 g_assert_cmpint(ret, ==, 0);
293
294 ret = send_unmap(qts, v_iommu, 1, 5, 9);
295 g_assert_cmpint(ret, ==, 0);
296
297
298 ret = send_map(qts, v_iommu, 1, 0, 4, 0xe2000, VIRTIO_IOMMU_MAP_F_READ);
299 g_assert_cmpint(ret, ==, 0);
300 ret = send_unmap(qts, v_iommu, 1, 0, 9);
301 g_assert_cmpint(ret, ==, 0);
302
303
304 ret = send_map(qts, v_iommu, 1, 0, 4, 0xf2000, VIRTIO_IOMMU_MAP_F_READ);
305 g_assert_cmpint(ret, ==, 0);
306 ret = send_map(qts, v_iommu, 1, 10, 14, 0xf3000, VIRTIO_IOMMU_MAP_F_READ);
307 g_assert_cmpint(ret, ==, 0);
308 ret = send_unmap(qts, v_iommu, 1, 0, 14);
309 g_assert_cmpint(ret, ==, 0);
310
311 ret = send_map(qts, v_iommu, 1, 10, 14, 0xf3000, VIRTIO_IOMMU_MAP_F_READ);
312 g_assert_cmpint(ret, ==, 0);
313 ret = send_map(qts, v_iommu, 1, 0, 4, 0xf2000, VIRTIO_IOMMU_MAP_F_READ);
314 g_assert_cmpint(ret, ==, 0);
315 ret = send_unmap(qts, v_iommu, 1, 0, 4);
316 g_assert_cmpint(ret, ==, 0);
317 ret = send_map(qts, v_iommu, 1, 10, 14, 0xf3000, VIRTIO_IOMMU_MAP_F_READ);
318 g_assert_cmpint(ret, ==, VIRTIO_IOMMU_S_INVAL);
319}
320
321static void register_virtio_iommu_test(void)
322{
323 qos_add_test("config", "virtio-iommu", pci_config, NULL);
324 qos_add_test("attach_detach", "virtio-iommu", test_attach_detach, NULL);
325 qos_add_test("map_unmap", "virtio-iommu", test_map_unmap, NULL);
326}
327
328libqos_init(register_virtio_iommu_test);
329