我想使用
ioremap_wc()
将设备内存(NIC)映射到内核空间内存区域。然后我想将内存区域从内核空间重新映射到用户空间,为此我可以使用 2 个函数:vm_insert_page()
和 remap_pfn_range()
POSIX
mmap(3)
通常使用第二个:remap_pfn_range()
vm_insert_page()
和 remap_pfn_range()
有什么区别,我什么时候需要使用 vm_insert_page()
而不是 remap_pfn_range()
?
顾名思义,
vm_insert_page()
映射一个单页,而remap_pfn_range()
映射一个连续的内核内存块。检查原型和注释vm_insert_page, remap_pfn_range
例如可以使用
vm_insert_page
来映射vmalloc
区域
do {
page = vmalloc_to_page(vaddr);
vm_insert_page(vma, uaddr, page);
vaddr += PAGE_SIZE;
} while(/* there is something to map */);
使用
remap_pfn_range
是不可能的,因为它只映射一个连续的内核内存块。
另一个区别是使用
remap_pfn_range
你不仅可以映射RAM缓冲区,还可以映射其他范围。使用 vm_inser_page
你可以只映射 RAM 缓冲区
Linus 的解释
vm_insert_page()
允许驱动程序将他们分配的单个页面插入到用户 vma 中。该页面必须在内核中独立分配。它要求页面是为此目的获得的零序分配。它不会发出警告,也不需要设置 PG_reserved。
传统上,这是通过
remap_pfn_range()
完成的,它采用任意页面保护参数。 vm_insert_page()
不允许这样。你的 vma 保护必须正确设置,这意味着如果你想要一个共享的可写映射,你最好要求一个共享的可写映射!
remap_pfn_range()
用于将一组页面映射或重新映射到内存中。
总结:
当您不需要
remap_pfn_range
作为物理页面框架时,请使用 struct page
。
使用 vm_insert_page
用于物理页面框架需要 struct page
的内存。
(请注意,还有 vm_insert_pages,它可以将多个页面插入 VMA。)
对于来自该区域的直接 I/O,使用
vm_insert_page/vm_insert_pages
,因为它们支持 get_user_page
以获得 struct page
,这是后续 ext4/scatterlist
代码所必需的。