Signed-off-by: Antonios Motakis <a.mota...@virtualopensystems.com>
---
 drivers/vfio/vfio_platform.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 44 insertions(+)

diff --git a/drivers/vfio/vfio_platform.c b/drivers/vfio/vfio_platform.c
index a0abcfa..6364316 100644
--- a/drivers/vfio/vfio_platform.c
+++ b/drivers/vfio/vfio_platform.c
@@ -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;
 }
 
-- 
1.8.1.2

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to