@@ -103,6 +103,10 @@ static long vfio_platform_ioctl(void *device_data,
info.offset = res.start; /* map phys addr with offset */
info.size = resource_size(&res);
info.flags = 0;
+ /* Only regions addressed with PAGE granularity can be MMAPed
+ * securely. */
+ if (!(info.offset & ~PAGE_MASK) && !(info.size & ~PAGE_MASK))
+ info.flags |= VFIO_REGION_INFO_FLAG_MMAP;
return copy_to_user((void __user *)arg, &info, minsz);
@@ -134,6 +138,18 @@ static long vfio_platform_ioctl(void *device_data,
return -ENOTTY;
}
+static bool is_in_resource(struct resource res, u64 addr, u64 size)
+{
+ if (addr < res.start)
+ return false;
+ if (addr > res.end)
+ return false;
+ if (addr + size - 1 > res.end)
+ return false;
+
+ return true;
+}
+
static ssize_t vfio_platform_read(void *device_data, char __user *buf,
size_t count, loff_t *ppos)
{
@@ -148,6 +164,34 @@ static ssize_t vfio_platform_write(void *device_data, const char __user *buf,
static int vfio_platform_mmap(void *device_data, struct vm_area_struct *vma)
{
+ struct vfio_platform_device *vdev = device_data;
+ struct device_node *of_node = vdev->pdev->dev.of_node;
+ u64 req_len = vma->vm_end - vma->vm_start;
+ u64 addr = vma->vm_pgoff << PAGE_SHIFT;
+ struct resource res;
+ int i;
+
+ if (vma->vm_end < vma->vm_start)
+ return -EINVAL;
+ if (vma->vm_start & ~PAGE_MASK)
+ return -EINVAL;
+ if (vma->vm_end & ~PAGE_MASK)
+ return -EINVAL;
+ if ((vma->vm_flags & VM_SHARED) == 0)
+ return -EINVAL;
+
+ for (i = 0; !of_address_to_resource(of_node, i, &res); i++) {
+ if (!is_in_resource(res, addr, req_len))
+ continue;
+
+ vma->vm_private_data = vdev;
+ vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP;
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+ return remap_pfn_range(vma, vma->vm_start, addr,
+ req_len, vma->vm_page_prot);
+ }
+
return -EINVAL;
}
Signed-off-by: Antonios Motakis <a.motakis@virtualopensystems.com> --- drivers/vfio/vfio_platform.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+)