[vfio-users] VFIO_IOMMU_MAP_DMA for address mapped from kernel via remap_pfn_range

Feng Li li2251 at purdue.edu
Wed Jul 10 18:49:33 UTC 2019


Hi,
I have some doubts in registering different types of memory for dma using vfio. Currently I have 4.15 kernel and have attached P4800X to vfio.
I followed the examples in the vfio kernel doc at (https://www.kernel.org/doc/Documentation/vfio.txt). Everything is fine with anonymous mapped memory in the example. I also tried to  register two other types of memory:

  1.  Mapped from device dax.
  2.  Kernel memory memory exposed to userspace using remap_pfn_range.

```
  switch (mem_type) {
  case MEM_TYPE_DEVDAX:
    // https://github.com/axboe/fio/blob/master/engines/dev-dax.c
    fd = open("/dev/dax0.0", O_RDWR, 0666);
    assert(fd != -1);
    ptr = mmap(NULL, map_size, PROT_READ | PROT_WRITE,
               MAP_SHARED, fd, 0);
    assert(ptr != MAP_FAILED);
    // memset(ptr, 0xff, map_size);

    break;

  case MEM_TYPE_DUMMYMAP:
    fd = open("/dev/dummymap", O_RDWR, 0666); // see below for dummymap kernel module
    assert(fd != -1);
    ptr = mmap(target_addr, map_size, PROT_READ | PROT_WRITE,
               MAP_SHARED | MAP_FIXED, fd, 0);
    assert(ptr != MAP_FAILED);
    // memset(ptr, 0xff, map_size);

    break;
  case MEM_TYPE_ANON_REGULAR:
  default:
    ptr = mmap(target_addr, map_size, PROT_READ | PROT_WRITE,
                         MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, 0, 0);
    assert(ptr != MAP_FAILED);
  }

  dma_map.vaddr = ptr;

  dma_map.size = map_size;

  dma_map.iova = 0x900000000; /* 1MB starting at 0x900000000 from device view */

  dma_map.flags = VFIO_DMA_MAP_FLAG_READ | VFIO_DMA_MAP_FLAG_WRITE;



  if (0 > ioctl(container, VFIO_IOMMU_MAP_DMA, &dma_map)) {

    PERR("VFIO_IO_MMU_MAP_DMA failed with errno %s", strerror(errno));

    return -1;

  } else {

    PINF("DMA memory setup succeed!");

  }


```

The "dummy map" is a kernel module which allocates kernel memory and map it to user space using remap_pfn_range:
```

static int fop_mmap(struct file *file, struct vm_area_struct *vma) {

  size_t map_size;

  void *dma_virtaddr;

  // dma_addr_t dma_handle;

  map_size = vma->vm_end - vma->vm_start;

  printk(KERN_INFO "dummy map mmap called!\n");



  /*dma_virtaddr = dma_alloc_coherent(dummymap_dev.this_device, map_size,*/

                                    /*&dma_handle, GFP_KERNEL);*/



  dma_virtaddr = kmalloc(map_size, GFP_KERNEL);

  if (!dma_virtaddr) {

    printk(KERN_ERR "dummy map failed in  memory allocation");

    return -ENOMEM;

  }

  vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);



  if (remap_pfn_range(vma, vma->vm_start,

                      virt_to_phys(dma_virtaddr) >> PAGE_SHIFT, map_size,

                      vma->vm_page_prot))

    return -ENOMEM;



  vma->vm_ops = &dummymap_fops;

  vm_open(vma);

  pr_info("dummy map succeed");

  return 0;

}

```

What happened is

  1.  the "devdax" registration seems to succeed.  I will do further tests on actual DMA. (I hope I am doing the right thing, am I?)
  2.  The "dummy map" approach failed at the VFIO_IOMMU_MAP_DMA ioctl (with errno = -14), I guess it violated some memory requirements for DMA using vfio, does anyone have any suggestions on this?.

I tracked into the kernel source and found out that the vaddr_get_pfn requires Pg_reserved bit set for VM_PFNMAP mappings(which is set from remap_pfn_range)... So I guess I needs somehow allocate memory with Pg_reserved set, but how?
I also left my code in https://github.com/fengggli/dumymap/commit/c562cd863ec0f6d921a7ae42ecfad0dbfc9d9d0b , if anyone wants to have a try.

Thanks
Feng Li
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://listman.redhat.com/archives/vfio-users/attachments/20190710/a6eefc60/attachment.htm>


More information about the vfio-users mailing list