首页 文章

内核中的物理内存分配

提问于
浏览
1

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

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

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

在此先感谢您的帮助 .

1 回答

  • 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() 的最简洁方法 .

相关问题