Linux用户空间应用程序是否有可能在不被IOMMU阻塞和不使用VFIO的情况下为DMA使用自己的内存?
当iommu被禁用(intel_iommu=off)或处于传递模式(intel_iommu=passthrough)时,我们的应用程序可以正常工作。但是,当启用IOMMU (intel_iommu=on)时,它不能工作,因为我们在用户空间中分配的内存不允许DMA。
官方的解决方案是使用Linux接口来管理IOMMU,但是我们认为VFIO特性还不是很成熟,我们更希望找到一个更简单的解决方案。
我们能否以某种方式指示IOMMU为我们分配的物理内存允许DMA?这将是很棒的,因为这样我们就不必指示我们的用户更改他们的内核引导参数。
如果有一个基于VFIO的简单可靠的解决方案,那么这也会很有趣。
有关如何分配内存的详细信息,请参阅前面的相关问题:mremap(2) with HugeTLB to change virtual address?
发布于 2015-05-01 12:11:23
您可以编写一个简单的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
https://stackoverflow.com/questions/29985296
复制相似问题