我正在 DMA 的设备驱动程序中重新实现 mmap
。
我看到这个问题: Linux 驱动程序:mmap() 内核不使用 nopage 缓冲到用户空间,其答案是使用 vm_insert_page()
一次映射一页;因此,对于多个页面,需要循环执行。是否有另一个 API 可以处理这个问题?
之前,我使用 dma_alloc_coherent 为 DMA 分配一块内存,并使用 remap_pfn_range 构建一个页表,将进程的虚拟内存与物理内存关联起来。
现在我想使用 __get_free_pages 分配更大的内存块,其顺序大于 1。我不确定在这种情况下如何构建页表。原因如下:
我查了Linux Device Drivers这本书,注意到以下内容:
背景:
当用户空间进程调用 mmap 将设备内存映射到其地址空间时,系统会通过创建一个新的 VMA 来表示该映射来做出响应。支持 mmap(因此实现 mmap 方法)的驱动程序需要通过完成该 VMA 的初始化来帮助该过程。
remap_pfn_range
出现问题:
remap_pfn_range
不允许您重新映射常规地址,其中包括通过调用 get_free_page
获取的地址。相反,它映射到零页。一切似乎都正常,除了进程看到私有的、零填充的页面,而不是它所希望的重新映射的 RAM。
在 scullp 设备驱动程序中使用 get_free_pages
顺序为 0,即只有 1 页的相应实现:
如果分配顺序大于零,则 scullp 设备的 mmap 方法将被禁用,因为 nopage 处理单个页面而不是页面簇。 scullp 根本不知道如何正确管理属于高阶分配的页面的引用计数。
我想知道是否有办法为使用 __get_free_pages
获取的顺序大于 1 的页面创建 VMA?
我检查了Linux源代码,发现有一些驱动程序重新实现了struct dma_map_ops->alloc()
和struct dma_map_ops->map_page()
。我可以知道这是否是正确的方法?
I am re-implementing mmap
in a device driver for DMA.
I saw this question: Linux Driver: mmap() kernel buffer to userspace without using nopage that has an answer using vm_insert_page()
to map one page at a time; hence, for multiple pages, needed to execute in a loop. Is there another API that handles this?
Previously I used dma_alloc_coherent
to allocate a chunk of memory for DMA and used remap_pfn_range
to build a page table that associates process's virtual memory to physical memory.
Now I would like to allocate a much larger chunk of memory using __get_free_pages
with order greater than 1. I am not sure how to build page table in that case. The reason is as follows:
I checked the book Linux Device Drivers and noticed the following:
Background:
When a user-space process calls mmap to map device memory into its address space, the system responds by creating a new VMA to represent that mapping. A driver that supports mmap (and, thus, that implements the mmap method) needs to help that process by completing the initialization of that VMA.
Problem with remap_pfn_range
:
remap_pfn_range
won’t allow you to remap conventional addresses, which include the ones you obtain by calling get_free_page
. Instead, it maps in the zero page. Everything appears to work, with the exception that the process sees private, zero-filled pages rather than the remapped RAM that it was hoping for.
The corresponding implementation using get_free_pages
with order 0, i.e. only 1 page in scullp device driver:
The mmap method is disabled for a scullp device if the allocation order is greater than zero, because nopage deals with single pages rather than clusters of pages. scullp simply does not know how to properly manage reference counts for pages that are part of higher-order allocations.
May I know if there is a way to create VMA for pages obtained using __get_free_pages
with order greater than 1?
I checked Linux source code and noticed there are some drivers re-implementing struct dma_map_ops->alloc()
and struct dma_map_ops->map_page()
. May I know if this is the correct way to do it?
发布评论
评论(1)
我想我得到了问题的答案。如果我错了,请随时纠正我。
我碰巧看到这个补丁: mm:介绍新的当我在谷歌上搜索
vm_insert_page
时,我使用了 vm_map_pages() 和 vm_map_pages_zero() API。读完之后,我知道我找到了我想要的东西。
该函数也可以在 Linux 中找到内核核心 API 文档。
至于
remap_pfn_range()
和vm_insert_page()
之间的区别(需要循环连续页面列表),我发现了这个 对此 href="https://stackoverflow.com/questions/27468083/what-is-the-difference- Between-vm-insert-page-and-remap-pfn-range">问题非常有帮助,其中它包含 Linus 的解释的链接。作为旁注,此补丁 mm:引入新的 vm_insert_range 和 vm_insert_range_buggy API< /a> 表示
vm_map_pages()
的早期版本是vm_insert_range()
,但我们应该坚持使用vm_map_pages()
,因为在底层vm_map_pages()
调用vm_insert_range().
I think I got the answer to my question. Feel free to correct me if I am wrong.
I happened to see this patch: mm: Introduce new vm_map_pages() and vm_map_pages_zero() API while I was googling for
vm_insert_page
.After reading it, I knew I found what I want.
That function also could be found in Linux Kernel Core API Documentation.
As for the difference between
remap_pfn_range()
andvm_insert_page()
which requires a loop for a list of contiguous pages, I found this answer to this question extremely helpful, in which it includes a link to explanation by Linus.As a side note, this patch mm: Introduce new vm_insert_range and vm_insert_range_buggy API indicates that the earlier version of
vm_map_pages()
wasvm_insert_range()
, but we should stick tovm_map_pages()
, since under the hoodvm_map_pages()
callsvm_insert_range()
.