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