内核中的物理内存分配

时间:2014-07-03 13:45:00

标签: memory-management linux-kernel kernel-module device-driver

我正在编写一个内核模块,它将触发并从​​外部PCIe设备读取我的内部存储器中的数据块。为此,我需要向PCIe设备发送指向我想要发送的数据的物理内存地址的指针。最终,这些数据将使用write()函数(用户空间)和copy_from_user()(内核空间)从用户空间写入内核。据我了解,我的内核模块将看到的地址仍然是虚拟内存地址。我需要一种方法来获取它的物理地址,以便PCIe设备可以找到它。

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

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

先谢谢你的帮助。

1 个答案:

答案 0 :(得分:2)

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

API就是:dma_map_page()返回类型dma_addr_t的值,您可以将其提供给电路板。转移完成后再dma_unmap_page()。如果您正在进行分散 - 聚集,则将该值替换为您提供给电路板的描述符列表。同样,如果支持scatter-gather,dma_map_sg()和朋友将帮助将大缓冲区映射到一组页面。您仍有责任以设备所需的格式设置页面描述符。

这一切都在Linux设备驱动程序(第15章)中写得非常好,这是必读的。 http://lwn.net/images/pdf/LDD3/ch15.pdf。一些API在书写之后发生了变化,但概念保持不变。

最后,mmap():当然,您可以将内核缓冲区mmap()分配给用户空间并将其填充到那里,然后将dma_map缓冲区传输到设备。事实上,这可能是避免copy_from_user()的最简洁方法。