linux-kernel - Linux 用户空间中通过/dev/mem 与 PCIe 设备进行双向通信?

标签 linux-kernel driver linux-device-driver embedded-linux pci-e

很确定我已经知道这个问题的答案,因为已经有相关问题了( herehereherethis 很有用),,,但我想在我深入内核空间驱动程序领域(以前从未去过那里)之前,请绝对确定。

我有一个 PCIe 设备,需要从 Linux 用户空间中的应用程序与其进行通信(反之亦然)。通过打开 /dev/mem,然后使用 mmap,我已经能够编写一个基于 pciutils 构建的用户空间驱动程序。这使我能够mmap BAR 并成功将数据写入设备。现在,我们需要 comm 走向另一个方向,从 PCIe 设备到 Linux 用户应用程序。为了实现这一点,我们相信我们将需要一大块(~100MB)物理上连续的内存,并且永远不会被分页/交换。一旦分配,该地址将需要传递到 PCIe 设备,以便它知道在哪里写入数据(因此我不明白这怎么可能是虚拟的、可交换的内存)。有没有办法在没有内核空间驱动程序的情况下做到这一点?这里提出了一个想法,也许我们可以打开/dev/mem,然后向其提供一个 ioctl 命令来分配我们需要的内容?如果这是可能的,我还无法在网上找到任何示例,并且需要进行更深入的研究。

假设我们需要一个内核空间驱动程序,最好在启动期间分配我们的大chuck,然后使用ioremap获取内核虚拟地址,然后mmap到用户空间,对吗?根据我在 kmalloc 上读到的内容,使用该调用我们不会获得接近 100MB 的内存,而且 vmalloc 也不好,因为那是虚拟内存。为了在启动时分配,驱动程序应该静态链接到内核中,对吗?这基本上是一个嵌入式应用程序,因此可移植性对我来说并不是一个大问题。模块而不是静态链接的驱动程序可能可以工作,但我担心内存碎片可能会阻止找到物理上连续的区域,所以我想在开机后尽快分配它。有任何反馈吗?

EDIT1:我的CPU是ARM7架构。

最佳答案

大页-1G

当前的 x86_64 处理器不仅支持 4k 和 2M,还支持 1G 页(/proc/cpuinfo 中的标志 pdpe1gb 表示支持)。

这些 1G 页必须已在内核启动时保留,因此必须指定启动参数 hugepagesz=1GB Hugepages=1

然后,必须安装hugetlbfs:

mkdir /hugetlb-1G
mount -t hugetlbfs -o pagesize=1G none /hugetlb-1G

然后打开一些文件并映射它:

fd = open("/hugetlb-1G/page-1", O_CREAT | O_RDWR, 0755);
addr = mmap(NULL, SIZE_1G, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);

您现在可以访问 addr 处的 1G 物理连续内存。为了确保它不会被交换,您可以使用 mlock (但这对于大页面来说可能根本没有必要)。

即使你的进程崩溃了,大页面也会被保留来映射它,就像上面一样,所以 pci-e 设备不会将恶意数据写入系统或进程内存。

通过读取/proc/pid/pagemap可以找到物理地址。

关于linux-kernel - Linux 用户空间中通过/dev/mem 与 PCIe 设备进行双向通信?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34887946/

相关文章:

linux - lock_page 对该页面以及引用/映射该页面的进程有什么影响?

linux-device-driver - 内核空间动态分配

c - 如何从下载的 Linux 源代码编译模块?

linux-kernel - `ioctl`读写GPIO : invalid argument

c - kmalloc 分配实际上不是连续的吗?

linux - 在 Linux 上唤醒 cpu 调用哪个函数

memory - 我们可以在内核模块中使用 virt_to_phys 作为用户空间内存吗?

linux - 如何在驱动程序代码内将 Linux 中的内核空间 VA 转换为 PA?

android - LG L90 不安装调试 USB 驱动程序

linux 驱动程序从用户空间使用 DMA 进行数据传输