Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/jsf-2/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Linux kernel 通过Linux用户空间中的/dev/mem与PCIe设备进行双向通信?_Linux Kernel_Driver_Linux Device Driver_Embedded Linux_Pci E - Fatal编程技术网

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

Linux kernel 通过Linux用户空间中的/dev/mem与PCIe设备进行双向通信?,linux-kernel,driver,linux-device-driver,embedded-linux,pci-e,Linux Kernel,Driver,Linux Device Driver,Embedded Linux,Pci E,非常肯定我已经知道这个问题的答案了,因为已经有相关的问题了(,和,,,和是有用的),,,但我想在深入内核空间驱动程序领域(以前从未有过)之前绝对确定 我有一个PCIe设备,需要从linux用户空间中的应用程序与之通信(反之亦然)。通过打开/dev/mem,然后mmap'ing,我已经能够编写一个构建在上面的用户空间驱动程序,它允许我mmap条并成功地将数据写入设备。现在,我们需要通信转到另一个方向,从PCIe设备到linux用户应用程序。为了实现这一点,我们认为需要一大块(约100MB)的物理连

非常肯定我已经知道这个问题的答案了,因为已经有相关的问题了(,和,,,和是有用的),,,但我想在深入内核空间驱动程序领域(以前从未有过)之前绝对确定

我有一个PCIe设备,需要从linux用户空间中的应用程序与之通信(反之亦然)。通过打开
/dev/mem
,然后
mmap
'ing,我已经能够编写一个构建在上面的用户空间驱动程序,它允许我
mmap
条并成功地将数据写入设备。现在,我们需要通信转到另一个方向,从PCIe设备到linux用户应用程序。为了实现这一点,我们认为需要一大块(约100MB)的物理连续内存,这些内存永远不会被分页/交换。一旦分配,该地址将需要传递给PCIe设备,以便它知道在哪里写入其数据(因此我不认为这是虚拟的、可交换的内存)。没有内核空间驱动程序,有没有办法做到这一点?这里提出了一个想法,也许我们可以打开
/dev/mem
,然后给它一个
ioctl
命令来分配我们需要的东西?如果这是可能的,我还没有在网上找到任何例子,需要更深入地研究

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


EDIT1:我的CPU是ARM7架构。

Hugepages-1G

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

这些1G页面必须在内核引导时保留,因此必须指定引导参数
hugepagesz=1GB hugepages=1

然后,必须安装HugetLBF:

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(但对于hugepages来说,这可能根本不是必需的)

即使您的进程崩溃,也会保留巨大的页面,以便像上面那样映射它,因此pci-e设备不会将rogue写入系统或进程内存


您可以通过阅读
/proc/pid/pagemap

找到物理地址实际上,Ctx关于
memmap
的评论让我走上了正确的道路。为了保留内存,我给出了一个bootloader参数,如我找到的
memmap=[size]$[location]
。不同的符号意味着不同的东西,它们并不完全是直观的。只是另一个轻微的修正,标志是
CONFIG\u STRICT\u DEVMEM
,我的内核没有使用它编译


还有一些谜团。例如,
memmap
参数中的
[location]
似乎没有意义。无论我为位置设置了什么,linux都将所有未使用
[size]
保留的内容放在一个连续的块中,而我保留的空间就在最后。唯一的迹象是查看
/proc/iomem
。我保留的空间量与linux内存空间末端和系统内存空间末端之间的间隙相匹配。除了linux在
/proc/iomem
中没有使用它之外,我在任何地方都找不到linux说“我看到了你的保留块,我不会碰它”的迹象。但是FPGA已经在这个领域写了好几天了,对linux没有明显的不良影响,所以我想我们都很好!我只需将mmap映射到该位置并读取数据(令人惊讶的是,linux并没有指出存在这种情况,但很高兴它确实存在)。谢谢你的帮助!Ian如果我转到内核驱动程序空间,我会回到你的评论。

shot,我可能应该提到我使用的CPU(至少现在)是ARM7架构。我不确定这是否会让你的答案变得毫无意义。不过,非常感谢您提供的信息,我肯定会在未来几天探索这种方法。我认为,32位arm没有1G的hugepages(尽管可能更小)。另一种方法是保留部分内存(例如,kernelbootparameter
memmap=100M@0x10000000
在1G物理内存中保留100MB),并将其从/dev/mem映射到进程内存中。您必须确保内核没有使用CONFIG_DEVMEM_STRICT编译,但是对于内核空间驱动程序,
dma_alloc_coherent
可以分配适合设备和CPU访问的内存。
mmap
的驱动程序文件操作处理程序可以调用
dma_mmap_coherent
将其映射到用户的地址空间。困难在于,您可以使用
dma\u alloc\u coherent
分配的内存大小通常非常有限。您可以使用
cma
内核引导参数来克服这一问题,例如
cma=100M
。实际上,您通常需要将
cma
参数设置得比您需要的大,因为其他驾驶员可能会在您的驾驶员之前窃取一些参数。