3

Linux 用户空间应用程序是否可以在不被 IOMMU 阻塞且不使用 VFIO 的情况下将自己的内存用于 DMA?

当 iommu 被禁用 (intel_iommu=off) 或处于直通模式 (intel_iommu=passthrough) 时,我们的应用程序工作正常。但是,当启用 IOMMU (intel_iommu=on) 时它不起作用,因为我们在用户空间中分配的内存不允许用于 DMA。

官方的解决方案是使用 Linux VFIO 接口来管理 IOMMU,但是我们觉得 VFIO 特性还不是很成熟,希望找到一个更简单的解决方案。

我们能否以某种方式指示 IOMMU 允许对我们分配的物理内存进行 DMA 访问?这将是美妙的,因为这样我们就不必指示我们的用户更改他们的内核引导参数。

如果有一个基于 VFIO 的简单可靠的解决方案,那也很有趣。

有关我们如何分配内存的详细信息,请参阅相关的先前问题: mremap(2) with HugeTLB to change virtual address?

4

1 回答 1

1

您可以编写一个简单的 char 设备驱动程序来执行此操作。

内部驱动程序(伪代码):

static ssize_t device_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
{
    struct page *page;
    dma_addr_t DmaBusAddress;

    copy_from_user(addrstr, buf, sizeof(addrstr));

    uaddr = simple_strtoul(addrstr, NULL, 0);

    /* Get page structure which describes your user space 
       memory area 
    */
    res = get_user_pages(...,uaddr,...&page);

    /* (optional)Get the kernel virtual address for your user space page  
    */
    kernel_virtual_address = kmap(page);

    DmaBusAddress = dma_map_page(...,page)

    /*
    or the function below if you use address instead of page

    DmaBusAddress  = dma_map_single(...kernel_virtual_address,count...);

    */

    dev->dma_dir = DMA_TO_DEVICE;/* Write operation */
    dev->dma_size = count;
    dev->dma_addr = DmaBusAddress;

    /* Assume you have already memory map your DMA controller's I/O space 
      with remap_pfn_range() */

    writeRegister(DMA_ADDRESS,dev->dma_addr);
    ........................

    writeRegister(START_DMA_TRANSFER,1); /* enable DMA controller */

}

上面的代码显示了如何使用通用 DMA 层。

引自 ldd3

“IOMMU 可以安排任何物理内存出现在设备可访问的地址范围内,它可能导致物理上分散的缓冲区看起来与设备连续。使用 IOMMU 需要使用通用 DMA 层;virt_to_bus 未启动到任务”

“通用 DMA 层竭尽全力确保一切在所有架构上都能正常工作,但是,正如我们将看到的,正确的行为需要遵守一小部分规则。”

“内存映射和 DMA”一章可能会回答您的所有问题。

这是链接: http: //free-electrons.com/doc/books/ldd3.pdf

于 2015-05-01T12:11:23.347 回答