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