如果使用阶数大于 1 的 __get_free_pages() 如何创建 vm_area 映射?

发布于 2025-01-11 18:30:23 字数 1338 浏览 0 评论 0 原文

我正在 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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

吃→可爱长大的 2025-01-18 18:30:23

我想我得到了问题的答案。如果我错了,请随时纠正我。

我碰巧看到这个补丁: mm:介绍新的当我在谷歌上搜索 vm_insert_page 时,我使用了 vm_map_pages() 和 vm_map_pages_zero() API

以前的驱动程序有自己的方式将内核页面/内存范围映射到用户 vma,这是通过在循环内调用 vm_insert_page() 来完成的。

由于这种模式在不同的驱动程序中很常见,因此可以通过创建新函数并在驱动程序中使用它来对其进行概括。

vm_map_pages() 是一个 API,可用于在考虑了 vm_pgoff 的驱动程序中映射内核内存/页面。

读完之后,我知道我找到了我想要的东西。

该函数也可以在 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.

Previouly drivers have their own way of mapping range of kernel pages/memory into user vma and this was done by invoking vm_insert_page() within a loop.

As this pattern is common across different drivers, it can be generalized by creating new functions and use it across the drivers.

vm_map_pages() is the API which could be used to mapped kernel memory/pages in drivers which has considered vm_pgoff.

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() and vm_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() was vm_insert_range(), but we should stick to vm_map_pages(), since under the hood vm_map_pages() calls vm_insert_range().

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文