Message ID | 6fef9ff9944381d51dd18f83ec03785a26754dcf.1712978213.git.nicolinc@nvidia.com |
---|---|
State | Handled Elsewhere |
Headers | show |
Series | Add Tegra241 (Grace) CMDQV Support (part 2/2) | expand |
On Fri, Apr 12, 2024 at 08:47:10PM -0700, Nicolin Chen wrote: > Add for sharing the kernel page with user space. This allows to pass > through HW resource (VCMDQ MMIO pages for example) to user space VMM > and guest OS. Use vma->vm_pgoff as the carrier of a viommu_id. > > Signed-off-by: Nicolin Chen <nicolinc@nvidia.com> > --- > drivers/iommu/iommufd/main.c | 40 ++++++++++++++++++++++++++++++++++++ > include/linux/iommufd.h | 4 ++++ > 2 files changed, 44 insertions(+) > > diff --git a/drivers/iommu/iommufd/main.c b/drivers/iommu/iommufd/main.c > index 96ef81530809..5b401c80cca8 100644 > --- a/drivers/iommu/iommufd/main.c > +++ b/drivers/iommu/iommufd/main.c > @@ -16,6 +16,7 @@ > #include <linux/mutex.h> > #include <linux/bug.h> > #include <uapi/linux/iommufd.h> > +#include <linux/iommu.h> > #include <linux/iommufd.h> > > #include "io_pagetable.h" > @@ -427,11 +428,50 @@ static long iommufd_fops_ioctl(struct file *filp, unsigned int cmd, > return ret; > } > > +static int iommufd_fops_mmap(struct file *filp, struct vm_area_struct *vma) > +{ > + struct iommufd_ctx *ictx = filp->private_data; > + size_t size = vma->vm_end - vma->vm_start; > + u32 viommu_id = (u32)vma->vm_pgoff; Don't do mmaps this way, it doesn't scale well for future things. The pgoff/length should *always* come from the kernel as some 'mmap_offset' output. I usually call this the mmap cookie. In this case have the mmap cookie for the tegra doorbell return in the viommu's driver data struct, then userspace just passes the opaque cookie to mmap to get the correct tegra doorbell. The core code has some simple xarray/maple tree to allocate cookies and dispatch them to the correct mmap callback. Usually I'd say to provide a mmap callback pointer when allocating the cookie. Also look at the RDMA Code around mmap there is a bunch of VMA validations needed. Ie we must insist on VM_SHARED and check permissions, etc. Jason
On Sun, May 12, 2024 at 12:19:12PM -0300, Jason Gunthorpe wrote: > On Fri, Apr 12, 2024 at 08:47:10PM -0700, Nicolin Chen wrote: > > Add for sharing the kernel page with user space. This allows to pass > > through HW resource (VCMDQ MMIO pages for example) to user space VMM > > and guest OS. Use vma->vm_pgoff as the carrier of a viommu_id. > > > > Signed-off-by: Nicolin Chen <nicolinc@nvidia.com> > > --- > > drivers/iommu/iommufd/main.c | 40 ++++++++++++++++++++++++++++++++++++ > > include/linux/iommufd.h | 4 ++++ > > 2 files changed, 44 insertions(+) > > > > diff --git a/drivers/iommu/iommufd/main.c b/drivers/iommu/iommufd/main.c > > index 96ef81530809..5b401c80cca8 100644 > > --- a/drivers/iommu/iommufd/main.c > > +++ b/drivers/iommu/iommufd/main.c > > @@ -16,6 +16,7 @@ > > #include <linux/mutex.h> > > #include <linux/bug.h> > > #include <uapi/linux/iommufd.h> > > +#include <linux/iommu.h> > > #include <linux/iommufd.h> > > > > #include "io_pagetable.h" > > @@ -427,11 +428,50 @@ static long iommufd_fops_ioctl(struct file *filp, unsigned int cmd, > > return ret; > > } > > > > +static int iommufd_fops_mmap(struct file *filp, struct vm_area_struct *vma) > > +{ > > + struct iommufd_ctx *ictx = filp->private_data; > > + size_t size = vma->vm_end - vma->vm_start; > > + u32 viommu_id = (u32)vma->vm_pgoff; > > Don't do mmaps this way, it doesn't scale well for future things. > > The pgoff/length should *always* come from the kernel as some > 'mmap_offset' output. I usually call this the mmap cookie. > > In this case have the mmap cookie for the tegra doorbell return in the > viommu's driver data struct, then userspace just passes the opaque > cookie to mmap to get the correct tegra doorbell. > > The core code has some simple xarray/maple tree to allocate cookies > and dispatch them to the correct mmap callback. Usually I'd say to > provide a mmap callback pointer when allocating the cookie. > > Also look at the RDMA Code around mmap there is a bunch of VMA > validations needed. Ie we must insist on VM_SHARED and check > permissions, etc. Yea, the vm_pgoff as a carrier is a bit of hack, as mentioned in the cover-letter. Let me revisit the whole thing and study from RDMA code also. Thanks Nicolin
diff --git a/drivers/iommu/iommufd/main.c b/drivers/iommu/iommufd/main.c index 96ef81530809..5b401c80cca8 100644 --- a/drivers/iommu/iommufd/main.c +++ b/drivers/iommu/iommufd/main.c @@ -16,6 +16,7 @@ #include <linux/mutex.h> #include <linux/bug.h> #include <uapi/linux/iommufd.h> +#include <linux/iommu.h> #include <linux/iommufd.h> #include "io_pagetable.h" @@ -427,11 +428,50 @@ static long iommufd_fops_ioctl(struct file *filp, unsigned int cmd, return ret; } +static int iommufd_fops_mmap(struct file *filp, struct vm_area_struct *vma) +{ + struct iommufd_ctx *ictx = filp->private_data; + size_t size = vma->vm_end - vma->vm_start; + u32 viommu_id = (u32)vma->vm_pgoff; + struct iommufd_viommu *viommu; + unsigned long pfn; + int rc; + + if (size > PAGE_SIZE) + return -EINVAL; + + viommu = container_of(iommufd_get_object(ictx, viommu_id, + IOMMUFD_OBJ_VIOMMU), + struct iommufd_viommu, obj); + if (IS_ERR(viommu)) + return PTR_ERR(viommu); + + if (!viommu->ops->get_mmap_pfn) { + rc = -EOPNOTSUPP; + goto out_put_viommu; + } + + pfn = viommu->ops->get_mmap_pfn(viommu, size); + if (!pfn) { + rc = -ENOMEM; + goto out_put_viommu; + } + + vma->vm_pgoff = 0; + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + vm_flags_set(vma, VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP); + rc = remap_pfn_range(vma, vma->vm_start, pfn, size, vma->vm_page_prot); +out_put_viommu: + iommufd_put_object(ictx, &viommu->obj); + return rc; +} + static const struct file_operations iommufd_fops = { .owner = THIS_MODULE, .open = iommufd_fops_open, .release = iommufd_fops_release, .unlocked_ioctl = iommufd_fops_ioctl, + .mmap = iommufd_fops_mmap, }; /** diff --git a/include/linux/iommufd.h b/include/linux/iommufd.h index 707b6d4b20a3..4a9c6b281d35 100644 --- a/include/linux/iommufd.h +++ b/include/linux/iommufd.h @@ -104,6 +104,8 @@ struct iommufd_viommu { * the include/uapi/linux/iommufd.h header. * @vqueue_free: Free all driver-specific parts of an iommufd_vqueue. The memory * of the iommufd_vqueue will be free-ed by iommufd core + * @get_mmap_pfn: Return the PFN of a viommu given a finite size, for user space + * to mmap the page(s). */ struct iommufd_viommu_ops { void (*free)(struct iommufd_viommu *viommu); @@ -114,6 +116,8 @@ struct iommufd_viommu_ops { struct iommufd_viommu *viommu, const struct iommu_user_data *user_data); void (*vqueue_free)(struct iommufd_vqueue *vqueue); + unsigned long (*get_mmap_pfn)(struct iommufd_viommu *viommu, + size_t pgsize); }; struct iommufd_vqueue {
Add for sharing the kernel page with user space. This allows to pass through HW resource (VCMDQ MMIO pages for example) to user space VMM and guest OS. Use vma->vm_pgoff as the carrier of a viommu_id. Signed-off-by: Nicolin Chen <nicolinc@nvidia.com> --- drivers/iommu/iommufd/main.c | 40 ++++++++++++++++++++++++++++++++++++ include/linux/iommufd.h | 4 ++++ 2 files changed, 44 insertions(+)