On 10/27/2014 07:07 PM, Antonios Motakis wrote: > VFIO returns a file descriptor which we can use to manipulate the memory > regions of the device. Usually, the user will mmap memory regions that are > addressable on page boundaries, however for memory regions where this is > not the case we cannot provide mmap functionality due to security concerns. > For this reason we also need allow to read and write to the memory regions some rewording needed here > via the file descriptor. Implement this funcionality typo Regards Eric only for MMIO regions > of platform devices; PIO regions are not being handled at this point. > > Signed-off-by: Antonios Motakis <a.motakis@xxxxxxxxxxxxxxxxxxxxxx> > --- > drivers/vfio/platform/vfio_platform_common.c | 150 ++++++++++++++++++++++++++ > drivers/vfio/platform/vfio_platform_private.h | 1 + > 2 files changed, 151 insertions(+) > > diff --git a/drivers/vfio/platform/vfio_platform_common.c b/drivers/vfio/platform/vfio_platform_common.c > index 82de752..e10a8d0 100644 > --- a/drivers/vfio/platform/vfio_platform_common.c > +++ b/drivers/vfio/platform/vfio_platform_common.c > @@ -55,6 +55,10 @@ static int vfio_platform_regions_init(struct vfio_platform_device *vdev) > switch (resource_type(res)) { > case IORESOURCE_MEM: > vdev->regions[i].type = VFIO_PLATFORM_REGION_TYPE_MMIO; > + vdev->regions[i].flags |= VFIO_REGION_INFO_FLAG_READ; > + if (!(res->flags & IORESOURCE_READONLY)) > + vdev->regions[i].flags |= > + VFIO_REGION_INFO_FLAG_WRITE; > break; > case IORESOURCE_IO: > vdev->regions[i].type = VFIO_PLATFORM_REGION_TYPE_PIO; > @@ -74,6 +78,11 @@ err: > > static void vfio_platform_regions_cleanup(struct vfio_platform_device *vdev) > { > + int i; > + > + for (i = 0; i < vdev->num_regions; i++) > + iounmap(vdev->regions[i].ioaddr); > + > vdev->num_regions = 0; > kfree(vdev->regions); > } > @@ -176,15 +185,156 @@ static long vfio_platform_ioctl(void *device_data, > return -ENOTTY; > } > > +static ssize_t vfio_platform_read_mmio(struct vfio_platform_region reg, > + char __user *buf, size_t count, > + loff_t off) > +{ > + unsigned int done = 0; > + > + if (!reg.ioaddr) { > + reg.ioaddr = > + ioremap_nocache(reg.addr, reg.size); > + > + if (!reg.ioaddr) > + return -ENOMEM; > + } > + > + while (count) { > + size_t filled; > + > + if (count >= 4 && !(off % 4)) { > + u32 val; > + > + val = ioread32(reg.ioaddr + off); > + if (copy_to_user(buf, &val, 4)) > + goto err; > + > + filled = 4; > + } else if (count >= 2 && !(off % 2)) { > + u16 val; > + > + val = ioread16(reg.ioaddr + off); > + if (copy_to_user(buf, &val, 2)) > + goto err; > + > + filled = 2; > + } else { > + u8 val; > + > + val = ioread8(reg.ioaddr + off); > + if (copy_to_user(buf, &val, 1)) > + goto err; > + > + filled = 1; > + } > + > + > + count -= filled; > + done += filled; > + off += filled; > + buf += filled; > + } > + > + return done; > +err: > + return -EFAULT; > +} > + > static ssize_t vfio_platform_read(void *device_data, char __user *buf, > size_t count, loff_t *ppos) > { > + struct vfio_platform_device *vdev = device_data; > + unsigned int index = VFIO_PLATFORM_OFFSET_TO_INDEX(*ppos); > + loff_t off = *ppos & VFIO_PLATFORM_OFFSET_MASK; > + > + if (index >= vdev->num_regions) > + return -EINVAL; > + > + if (!(vdev->regions[index].flags & VFIO_REGION_INFO_FLAG_READ)) > + return -EINVAL; > + > + if (vdev->regions[index].type & VFIO_PLATFORM_REGION_TYPE_MMIO) > + return vfio_platform_read_mmio(vdev->regions[index], > + buf, count, off); > + else if (vdev->regions[index].type & VFIO_PLATFORM_REGION_TYPE_PIO) > + return -EINVAL; /* not implemented */ > + > return -EINVAL; > } > > +static ssize_t vfio_platform_write_mmio(struct vfio_platform_region reg, > + const char __user *buf, size_t count, > + loff_t off) > +{ > + unsigned int done = 0; > + > + if (!reg.ioaddr) { > + reg.ioaddr = > + ioremap_nocache(reg.addr, reg.size); > + > + if (!reg.ioaddr) > + return -ENOMEM; > + } > + > + while (count) { > + size_t filled; > + > + if (count >= 4 && !(off % 4)) { > + u32 val; > + > + if (copy_from_user(&val, buf, 4)) > + goto err; > + iowrite32(val, reg.ioaddr + off); > + > + filled = 4; > + } else if (count >= 2 && !(off % 2)) { > + u16 val; > + > + if (copy_from_user(&val, buf, 2)) > + goto err; > + iowrite16(val, reg.ioaddr + off); > + > + filled = 2; > + } else { > + u8 val; > + > + if (copy_from_user(&val, buf, 1)) > + goto err; > + iowrite8(val, reg.ioaddr + off); > + > + filled = 1; > + } > + > + count -= filled; > + done += filled; > + off += filled; > + buf += filled; > + } > + > + return done; > +err: > + return -EFAULT; > +} > + > static ssize_t vfio_platform_write(void *device_data, const char __user *buf, > size_t count, loff_t *ppos) > { > + struct vfio_platform_device *vdev = device_data; > + unsigned int index = VFIO_PLATFORM_OFFSET_TO_INDEX(*ppos); > + loff_t off = *ppos & VFIO_PLATFORM_OFFSET_MASK; > + > + if (index >= vdev->num_regions) > + return -EINVAL; > + > + if (!(vdev->regions[index].flags & VFIO_REGION_INFO_FLAG_WRITE)) > + return -EINVAL; > + > + if (vdev->regions[index].type & VFIO_PLATFORM_REGION_TYPE_MMIO) > + return vfio_platform_write_mmio(vdev->regions[index], > + buf, count, off); > + else if (vdev->regions[index].type & VFIO_PLATFORM_REGION_TYPE_PIO) > + return -EINVAL; /* not implemented */ > + > return -EINVAL; > } > > diff --git a/drivers/vfio/platform/vfio_platform_private.h b/drivers/vfio/platform/vfio_platform_private.h > index b24729f..1f251b2 100644 > --- a/drivers/vfio/platform/vfio_platform_private.h > +++ b/drivers/vfio/platform/vfio_platform_private.h > @@ -31,6 +31,7 @@ struct vfio_platform_region { > u32 type; > #define VFIO_PLATFORM_REGION_TYPE_MMIO 1 > #define VFIO_PLATFORM_REGION_TYPE_PIO 2 > + void __iomem *ioaddr; > }; > > struct vfio_platform_device { > _______________________________________________ kvmarm mailing list kvmarm@xxxxxxxxxxxxxxxxxxxxx https://lists.cs.columbia.edu/mailman/listinfo/kvmarm