首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在Linux中创建一个IOMMU条目

在Linux中创建一个IOMMU条目
EN

Stack Overflow用户
提问于 2022-07-07 07:13:37
回答 1查看 113关注 0票数 1

我已经浏览Linux代码很长一段时间了,无法找到一种直接创建IOMMU条目的简单方法。

我想指定物理地址(也可能是虚拟地址,但它不是必要的)和设备。范围应该插入到IOMMU和通过printk打印的virt地址中。

我正在寻找一个函数,让我可以轻松地完成它。

谢谢

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-07-08 13:33:36

最后,我得到了一个相当麻烦的解决方案,而不是最理想的解决方案,但它对我的使用是有效的。调整dma-iommu.c中的函数dma-iommu.c,使其如下所示,并导出它。

(香草5.18,但此项修改除外)

代码语言:javascript
复制
dma_addr_t iommu_dma_map_page(struct device *dev, struct page *page,
        unsigned long offset, size_t size, enum dma_data_direction dir,
        unsigned long attrs)
{
    bool coherent = dev_is_dma_coherent(dev);
    int prot = dma_info_to_prot(dir, coherent, attrs);
    struct iommu_domain *domain = iommu_get_dma_domain(dev);
    struct iommu_dma_cookie *cookie = domain->iova_cookie;
    struct iova_domain *iovad = &cookie->iovad;
    dma_addr_t iova, dma_mask = dma_get_mask(dev);
    phys_addr_t phys;
    if (page->flags == 0xF0F0F0F0F0F0F) {
        phys = page->dma_addr;
    } else {
        phys = page_to_phys(page) + offset;
    }

    /*
     * If both the physical buffer start address and size are
     * page aligned, we don't need to use a bounce page.
     */
    if (dev_use_swiotlb(dev) && iova_offset(iovad, phys | size)) {
        void *padding_start;
        size_t padding_size, aligned_size;

        aligned_size = iova_align(iovad, size);
        phys = swiotlb_tbl_map_single(dev, phys, size, aligned_size,
                          iova_mask(iovad), dir, attrs);

        if (phys == DMA_MAPPING_ERROR)
            return DMA_MAPPING_ERROR;

        /* Cleanup the padding area. */
        padding_start = phys_to_virt(phys);
        padding_size = aligned_size;

        if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC) &&
            (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL)) {
            padding_start += size;
            padding_size -= size;
        }

        memset(padding_start, 0, padding_size);
    }

    if (!coherent && !(attrs & DMA_ATTR_SKIP_CPU_SYNC))
        arch_sync_dma_for_device(phys, size, dir);

    iova = __iommu_dma_map(dev, phys, size, prot, dma_mask);
    if (iova == DMA_MAPPING_ERROR && is_swiotlb_buffer(dev, phys))
        swiotlb_tbl_unmap_single(dev, phys, size, dir, attrs);
    return iova;
}
EXPORT_SYMBOL(iommu_dma_map_page);

然后使用下面的内核模块对条目进行编程。这也可以用一种更有用的方式进行扩展和编程,但是对于原型化来说,它应该足够了。

代码语言:javascript
复制
#include <linux/init.h>
#include <asm/io.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/pci.h>

extern dma_addr_t iommu_dma_map_page(struct device *dev, struct page *page,
                                     unsigned long offset, size_t size, enum dma_data_direction dir,
                                     unsigned long attrs);

int magic_value = 0xF0F0F0F0F0F0F;

struct page page_ = {
    .flags = 0xF0F0F0F0F0F0F,
    .dma_addr = 0x0000002f000f0000,
};

static int my_init(void)
{
    dma_addr_t dma_addr;
    struct pci_dev *dummy = pci_get_device(0x10EE, 0x0666, NULL);
    if (dummy != NULL)
    {
        printk(KERN_INFO "module loaded.\n");
        dma_addr = iommu_dma_map_page(&(dummy->dev), &page_, 0, 4096, DMA_BIDIRECTIONAL, DMA_ATTR_SKIP_CPU_SYNC);
        printk(KERN_INFO "DMA_addr: %llx", dma_addr);
    }
    else
    {
        printk("Error getting device");
    }

    return 0;
}

static void my_exit(void)
{
    printk(KERN_INFO "iommu_alloc unloaded.\n");

    return;
}

module_init(my_init);
module_exit(my_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("benedict.schlueter@inf.ethz.ch");
MODULE_DESCRIPTION("Alloc IOMMU entry");
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72893653

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档