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