很确定我已经知道这个问题的答案,因为已经有相关问题了( here 、 here 和 here 和 this 很有用),,,但我想在我深入内核空间驱动程序领域(以前从未去过那里)之前,请绝对确定。
我有一个 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/