We report the real IOMMU geometry through the VFIO_IOMMU_GET_INFO ioctl call when the vfio_iommu_type1_info support capabilities. Signed-off-by: Pierre Morel <pmorel@xxxxxxxxxxxxx> --- drivers/vfio/vfio_iommu_type1.c | 43 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c index d9fd318..0a7746c 100644 --- a/drivers/vfio/vfio_iommu_type1.c +++ b/drivers/vfio/vfio_iommu_type1.c @@ -1673,6 +1673,23 @@ static int vfio_domains_have_iommu_cache(struct vfio_iommu *iommu) return ret; } +static int vfio_iommu_type1_caps(struct vfio_iommu *iommu, + struct vfio_info_cap *caps) +{ + struct vfio_domain *d; + struct vfio_iommu_cap_dma info = { .header.id = VFIO_IOMMU_INFO_CAP_DMA, + .header.version = 1 }; + int ret; + + d = list_first_entry(&iommu->domain_list, struct vfio_domain, next); + if (!d || !d->domain) + return -ENODEV; + info.dma_start = d->domain->geometry.aperture_start; + info.dma_end = d->domain->geometry.aperture_end; + ret = vfio_info_add_capability(caps, &info.header, sizeof(info)); + return ret; +} + static long vfio_iommu_type1_ioctl(void *iommu_data, unsigned int cmd, unsigned long arg) { @@ -1694,6 +1711,8 @@ static long vfio_iommu_type1_ioctl(void *iommu_data, } } else if (cmd == VFIO_IOMMU_GET_INFO) { struct vfio_iommu_type1_info info; + struct vfio_info_cap caps = { .buf = NULL, .size = 0 }; + int ret; minsz = offsetofend(struct vfio_iommu_type1_info, iova_pgsizes); @@ -1703,7 +1722,29 @@ static long vfio_iommu_type1_ioctl(void *iommu_data, if (info.argsz < minsz) return -EINVAL; - info.flags = VFIO_IOMMU_INFO_PGSIZES; + if (info.flags & VFIO_IOMMU_INFO_CAPABILITIES) { + ret = vfio_iommu_type1_caps(iommu, &caps); + if (ret) + return ret; + } + if (caps.size) { + if (info.argsz < sizeof(info) + caps.size) { + info.argsz = sizeof(info) + caps.size; + info.cap_offset = 0; + } else { + vfio_info_cap_shift(&caps, sizeof(info)); + if (copy_to_user((void __user *)arg + + sizeof(info), caps.buf, + caps.size)) { + kfree(caps.buf); + return -EFAULT; + } + info.cap_offset = sizeof(info); + } + kfree(caps.buf); + } + + info.flags |= VFIO_IOMMU_INFO_PGSIZES; info.iova_pgsizes = vfio_pgsize_bitmap(iommu); -- 2.7.4