Memory management 内核中的物理内存分配

Memory management 内核中的物理内存分配,memory-management,linux-kernel,kernel-module,device-driver,Memory Management,Linux Kernel,Kernel Module,Device Driver,我正在编写一个内核模块,该模块将触发和外部PCIe设备,以从我的internel内存中读取数据块。为此,我需要向PCIe设备发送指向我要发送的数据的物理内存地址的指针。最终,这些数据将通过write()函数(Userspace)和copy\u from\u user()(内核空间)从用户空间写入内核。据我所知,我的内核模块将看到的地址仍然是一个虚拟内存地址。我需要一种获取它的物理地址的方法,以便PCIe设备能够找到它 1) 我可以从用户空间使用mmap(),将数据放在DDR内存中的已知位置,而不

我正在编写一个内核模块,该模块将触发和外部PCIe设备,以从我的internel内存中读取数据块。为此,我需要向PCIe设备发送指向我要发送的数据的物理内存地址的指针。最终,这些数据将通过
write()
函数(Userspace)和
copy\u from\u user()
(内核空间)从用户空间写入内核。据我所知,我的内核模块将看到的地址仍然是一个虚拟内存地址。我需要一种获取它的物理地址的方法,以便PCIe设备能够找到它

1) 我可以从用户空间使用
mmap()
,将数据放在DDR内存中的已知位置,而不是使用
copy\u from\u user()
?但我不想意外地覆盖内存中的另一个进程数据

2) 我的内核模块在初始化时使用
ioremap\u nocache()
保留PCIe数据空间,我可以对我的内核模块执行同样的操作吗?还是将此内存视为io内存是一个坏主意?如果可以,如果我试图保留的内存已经在使用,会发生什么?我不想硬编码一个静态内存位置,然后发现它正在使用


提前感谢您的帮助。

您没有选择内存位置并将数据放在那里。相反,您要求内核告诉您数据在物理内存中的位置,并告诉电路板读取该位置。内存的每一页(4KB)将位于不同的物理位置,因此,如果您发送的数据超过该位置,您的设备可能支持“分散-聚集”DMA,因此它可以读取内存中不同位置的一系列页面

API是这样的:
dma\u map\u page()
返回类型为
dma\u addr\u t
的值,您可以将该值提供给电路板。然后,当传输完成时,
dma\u unmap\u page()
。如果您正在执行“分散-聚集”,您将把该值放在输入到电路板的描述符列表中。同样,如果支持分散聚集,
dma\u map\u sg()
和朋友们将帮助将一个大缓冲区映射到一组页面中。按照设备所需的格式设置页面描述符仍然是您的责任

这些都在Linux设备驱动程序(第15章)中写得很好,这是必读的。与本书编写时相比,一些API已经发生了变化,但概念保持不变


最后,
mmap()。事实上,这可能是避免从用户复制的最干净的方法。

好的,我并不是从我的终端开始DMA传输。PCIe总线上的端点正在从我的内存空间进行DMA读取。我还需要使用dma_map_page()吗?最终,我希望不必更改PCIe设备的条形图,因此我希望我的缓冲区位于特定的空间中。有选择吗?(我面前有LDD3)是的,总线控制DMA就是这样工作的。您正在告诉设备要在主机内存空间中读取哪些地址。酒吧与此毫无关系。它仅适用于设备中映射到内核空间的寄存器。您可以使用这些寄存器告诉设备从内存空间中的其他位置(任何地方!)获取数据,这就是
map\u page
的作用。我的答案正是你需要做的,而且是做DMA的标准方法。