xref: /qemu/hw/vfio/helpers.c (revision 090c9641882da217e40936c98742749e4cc94130)
11e09f52fSYi Liu /*
21e09f52fSYi Liu  * low level and IOMMU backend agnostic helpers used by VFIO devices,
31e09f52fSYi Liu  * related to regions, interrupts, capabilities
41e09f52fSYi Liu  *
51e09f52fSYi Liu  * Copyright Red Hat, Inc. 2012
61e09f52fSYi Liu  *
71e09f52fSYi Liu  * Authors:
81e09f52fSYi Liu  *  Alex Williamson <alex.williamson@redhat.com>
91e09f52fSYi Liu  *
101e09f52fSYi Liu  * This work is licensed under the terms of the GNU GPL, version 2.  See
111e09f52fSYi Liu  * the COPYING file in the top-level directory.
121e09f52fSYi Liu  *
131e09f52fSYi Liu  * Based on qemu-kvm device-assignment:
141e09f52fSYi Liu  *  Adapted for KVM by Qumranet.
151e09f52fSYi Liu  *  Copyright (c) 2007, Neocleus, Alex Novik (alex@neocleus.com)
161e09f52fSYi Liu  *  Copyright (c) 2007, Neocleus, Guy Zana (guy@neocleus.com)
171e09f52fSYi Liu  *  Copyright (C) 2008, Qumranet, Amit Shah (amit.shah@qumranet.com)
181e09f52fSYi Liu  *  Copyright (C) 2008, Red Hat, Amit Shah (amit.shah@redhat.com)
191e09f52fSYi Liu  *  Copyright (C) 2008, IBM, Muli Ben-Yehuda (muli@il.ibm.com)
201e09f52fSYi Liu  */
211e09f52fSYi Liu 
221e09f52fSYi Liu #include "qemu/osdep.h"
231e09f52fSYi Liu #include <sys/ioctl.h>
241e09f52fSYi Liu 
2554525613SCédric Le Goater #include "system/kvm.h"
26*11b8b9d5SCédric Le Goater #include "hw/vfio/vfio-device.h"
271e09f52fSYi Liu #include "hw/hw.h"
281e09f52fSYi Liu #include "qapi/error.h"
29ac28680dSCédric Le Goater #include "vfio-helpers.h"
301e09f52fSYi Liu 
vfio_bitmap_alloc(VFIOBitmap * vbmap,hwaddr size)311e09f52fSYi Liu int vfio_bitmap_alloc(VFIOBitmap *vbmap, hwaddr size)
321e09f52fSYi Liu {
331e09f52fSYi Liu     vbmap->pages = REAL_HOST_PAGE_ALIGN(size) / qemu_real_host_page_size();
341e09f52fSYi Liu     vbmap->size = ROUND_UP(vbmap->pages, sizeof(__u64) * BITS_PER_BYTE) /
351e09f52fSYi Liu                                          BITS_PER_BYTE;
361e09f52fSYi Liu     vbmap->bitmap = g_try_malloc0(vbmap->size);
371e09f52fSYi Liu     if (!vbmap->bitmap) {
381e09f52fSYi Liu         return -ENOMEM;
391e09f52fSYi Liu     }
401e09f52fSYi Liu 
411e09f52fSYi Liu     return 0;
421e09f52fSYi Liu }
431e09f52fSYi Liu 
441e09f52fSYi Liu struct vfio_info_cap_header *
vfio_get_cap(void * ptr,uint32_t cap_offset,uint16_t id)451e09f52fSYi Liu vfio_get_cap(void *ptr, uint32_t cap_offset, uint16_t id)
461e09f52fSYi Liu {
471e09f52fSYi Liu     struct vfio_info_cap_header *hdr;
481e09f52fSYi Liu 
491e09f52fSYi Liu     for (hdr = ptr + cap_offset; hdr != ptr; hdr = ptr + hdr->next) {
501e09f52fSYi Liu         if (hdr->id == id) {
511e09f52fSYi Liu             return hdr;
521e09f52fSYi Liu         }
531e09f52fSYi Liu     }
541e09f52fSYi Liu 
551e09f52fSYi Liu     return NULL;
561e09f52fSYi Liu }
571e09f52fSYi Liu 
581e09f52fSYi Liu struct vfio_info_cap_header *
vfio_get_region_info_cap(struct vfio_region_info * info,uint16_t id)591e09f52fSYi Liu vfio_get_region_info_cap(struct vfio_region_info *info, uint16_t id)
601e09f52fSYi Liu {
611e09f52fSYi Liu     if (!(info->flags & VFIO_REGION_INFO_FLAG_CAPS)) {
621e09f52fSYi Liu         return NULL;
631e09f52fSYi Liu     }
641e09f52fSYi Liu 
651e09f52fSYi Liu     return vfio_get_cap((void *)info, info->cap_offset, id);
661e09f52fSYi Liu }
671e09f52fSYi Liu 
681e09f52fSYi Liu struct vfio_info_cap_header *
vfio_get_device_info_cap(struct vfio_device_info * info,uint16_t id)691e09f52fSYi Liu vfio_get_device_info_cap(struct vfio_device_info *info, uint16_t id)
701e09f52fSYi Liu {
711e09f52fSYi Liu     if (!(info->flags & VFIO_DEVICE_FLAGS_CAPS)) {
721e09f52fSYi Liu         return NULL;
731e09f52fSYi Liu     }
741e09f52fSYi Liu 
751e09f52fSYi Liu     return vfio_get_cap((void *)info, info->cap_offset, id);
761e09f52fSYi Liu }
771e09f52fSYi Liu 
78f6d7f5d0SCédric Le Goater struct vfio_info_cap_header *
vfio_get_iommu_type1_info_cap(struct vfio_iommu_type1_info * info,uint16_t id)79f6d7f5d0SCédric Le Goater vfio_get_iommu_type1_info_cap(struct vfio_iommu_type1_info *info, uint16_t id)
80f6d7f5d0SCédric Le Goater {
81f6d7f5d0SCédric Le Goater     if (!(info->flags & VFIO_IOMMU_INFO_CAPS)) {
82f6d7f5d0SCédric Le Goater         return NULL;
83f6d7f5d0SCédric Le Goater     }
84f6d7f5d0SCédric Le Goater 
85f6d7f5d0SCédric Le Goater     return vfio_get_cap((void *)info, info->cap_offset, id);
86f6d7f5d0SCédric Le Goater }
87f6d7f5d0SCédric Le Goater 
vfio_get_info_dma_avail(struct vfio_iommu_type1_info * info,unsigned int * avail)88f6d7f5d0SCédric Le Goater bool vfio_get_info_dma_avail(struct vfio_iommu_type1_info *info,
89f6d7f5d0SCédric Le Goater                              unsigned int *avail)
90f6d7f5d0SCédric Le Goater {
91f6d7f5d0SCédric Le Goater     struct vfio_info_cap_header *hdr;
92f6d7f5d0SCédric Le Goater     struct vfio_iommu_type1_info_dma_avail *cap;
93f6d7f5d0SCédric Le Goater 
94f6d7f5d0SCédric Le Goater     /* If the capability cannot be found, assume no DMA limiting */
95f6d7f5d0SCédric Le Goater     hdr = vfio_get_iommu_type1_info_cap(info,
96f6d7f5d0SCédric Le Goater                                         VFIO_IOMMU_TYPE1_INFO_DMA_AVAIL);
97f6d7f5d0SCédric Le Goater     if (!hdr) {
98f6d7f5d0SCédric Le Goater         return false;
99f6d7f5d0SCédric Le Goater     }
100f6d7f5d0SCédric Le Goater 
101f6d7f5d0SCédric Le Goater     if (avail != NULL) {
102f6d7f5d0SCédric Le Goater         cap = (void *) hdr;
103f6d7f5d0SCédric Le Goater         *avail = cap->avail;
104f6d7f5d0SCédric Le Goater     }
105f6d7f5d0SCédric Le Goater 
106f6d7f5d0SCédric Le Goater     return true;
107f6d7f5d0SCédric Le Goater }
108f6d7f5d0SCédric Le Goater 
109c3fbdba1SCédric Le Goater #ifdef CONFIG_KVM
110c3fbdba1SCédric Le Goater /*
111c3fbdba1SCédric Le Goater  * We have a single VFIO pseudo device per KVM VM.  Once created it lives
112c3fbdba1SCédric Le Goater  * for the life of the VM.  Closing the file descriptor only drops our
113c3fbdba1SCédric Le Goater  * reference to it and the device's reference to kvm.  Therefore once
114c3fbdba1SCédric Le Goater  * initialized, this file descriptor is only released on QEMU exit and
115c3fbdba1SCédric Le Goater  * we'll re-use it should another vfio device be attached before then.
116c3fbdba1SCédric Le Goater  */
117c3fbdba1SCédric Le Goater int vfio_kvm_device_fd = -1;
118c3fbdba1SCédric Le Goater #endif
119c3fbdba1SCédric Le Goater 
vfio_kvm_device_add_fd(int fd,Error ** errp)12054525613SCédric Le Goater int vfio_kvm_device_add_fd(int fd, Error **errp)
12154525613SCédric Le Goater {
12254525613SCédric Le Goater #ifdef CONFIG_KVM
12354525613SCédric Le Goater     struct kvm_device_attr attr = {
12454525613SCédric Le Goater         .group = KVM_DEV_VFIO_FILE,
12554525613SCédric Le Goater         .attr = KVM_DEV_VFIO_FILE_ADD,
12654525613SCédric Le Goater         .addr = (uint64_t)(unsigned long)&fd,
12754525613SCédric Le Goater     };
12854525613SCédric Le Goater 
12954525613SCédric Le Goater     if (!kvm_enabled()) {
13054525613SCédric Le Goater         return 0;
13154525613SCédric Le Goater     }
13254525613SCédric Le Goater 
13354525613SCédric Le Goater     if (vfio_kvm_device_fd < 0) {
13454525613SCédric Le Goater         struct kvm_create_device cd = {
13554525613SCédric Le Goater             .type = KVM_DEV_TYPE_VFIO,
13654525613SCédric Le Goater         };
13754525613SCédric Le Goater 
13854525613SCédric Le Goater         if (kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd)) {
13954525613SCédric Le Goater             error_setg_errno(errp, errno, "Failed to create KVM VFIO device");
14054525613SCédric Le Goater             return -errno;
14154525613SCédric Le Goater         }
14254525613SCédric Le Goater 
14354525613SCédric Le Goater         vfio_kvm_device_fd = cd.fd;
14454525613SCédric Le Goater     }
14554525613SCédric Le Goater 
14654525613SCédric Le Goater     if (ioctl(vfio_kvm_device_fd, KVM_SET_DEVICE_ATTR, &attr)) {
14754525613SCédric Le Goater         error_setg_errno(errp, errno, "Failed to add fd %d to KVM VFIO device",
14854525613SCédric Le Goater                          fd);
14954525613SCédric Le Goater         return -errno;
15054525613SCédric Le Goater     }
15154525613SCédric Le Goater #endif
15254525613SCédric Le Goater     return 0;
15354525613SCédric Le Goater }
15454525613SCédric Le Goater 
vfio_kvm_device_del_fd(int fd,Error ** errp)15554525613SCédric Le Goater int vfio_kvm_device_del_fd(int fd, Error **errp)
15654525613SCédric Le Goater {
15754525613SCédric Le Goater #ifdef CONFIG_KVM
15854525613SCédric Le Goater     struct kvm_device_attr attr = {
15954525613SCédric Le Goater         .group = KVM_DEV_VFIO_FILE,
16054525613SCédric Le Goater         .attr = KVM_DEV_VFIO_FILE_DEL,
16154525613SCédric Le Goater         .addr = (uint64_t)(unsigned long)&fd,
16254525613SCédric Le Goater     };
16354525613SCédric Le Goater 
16454525613SCédric Le Goater     if (vfio_kvm_device_fd < 0) {
16554525613SCédric Le Goater         error_setg(errp, "KVM VFIO device isn't created yet");
16654525613SCédric Le Goater         return -EINVAL;
16754525613SCédric Le Goater     }
16854525613SCédric Le Goater 
16954525613SCédric Le Goater     if (ioctl(vfio_kvm_device_fd, KVM_SET_DEVICE_ATTR, &attr)) {
17054525613SCédric Le Goater         error_setg_errno(errp, errno,
17154525613SCédric Le Goater                          "Failed to remove fd %d from KVM VFIO device", fd);
17254525613SCédric Le Goater         return -errno;
17354525613SCédric Le Goater     }
17454525613SCédric Le Goater #endif
17554525613SCédric Le Goater     return 0;
17654525613SCédric Le Goater }
17754525613SCédric Le Goater 
vfio_get_device_info(int fd)178005b8d10SCédric Le Goater struct vfio_device_info *vfio_get_device_info(int fd)
179005b8d10SCédric Le Goater {
180005b8d10SCédric Le Goater     struct vfio_device_info *info;
181005b8d10SCédric Le Goater     uint32_t argsz = sizeof(*info);
182005b8d10SCédric Le Goater 
183005b8d10SCédric Le Goater     info = g_malloc0(argsz);
184005b8d10SCédric Le Goater 
185005b8d10SCédric Le Goater retry:
186005b8d10SCédric Le Goater     info->argsz = argsz;
187005b8d10SCédric Le Goater 
188005b8d10SCédric Le Goater     if (ioctl(fd, VFIO_DEVICE_GET_INFO, info)) {
189005b8d10SCédric Le Goater         g_free(info);
190005b8d10SCédric Le Goater         return NULL;
191005b8d10SCédric Le Goater     }
192005b8d10SCédric Le Goater 
193005b8d10SCédric Le Goater     if (info->argsz > argsz) {
194005b8d10SCédric Le Goater         argsz = info->argsz;
195005b8d10SCédric Le Goater         info = g_realloc(info, argsz);
196005b8d10SCédric Le Goater         goto retry;
197005b8d10SCédric Le Goater     }
198005b8d10SCédric Le Goater 
199005b8d10SCédric Le Goater     return info;
200005b8d10SCédric Le Goater }
201