如何使用remap_pfn_range将内核内存重新映射到用户空间?(涉及IT技术)

19

remap_pfn_range函数(在驱动程序中使用的mmap调用中)可用于将内核内存映射到用户空间。它是如何完成的?有人可以解释具体步骤吗?内核模式是特权模式(PM),而用户空间是非特权模式(NPM)。在 PM 中,CPU 可以访问所有内存,而在 NPM 中,一些内存受限制-不能被 CPU 访问。当调用 remap_pfn_range 时,之前仅限于 PM 的内存范围如何变得可访问用户空间呢?

remap_pfn_range 代码中可以看出,有一个pgprot_t结构。这是与保护映射相关的 struct。什么是保护映射?它是上述问题的答案吗?

2个回答

19

其实很简单,内核内存(通常)只有一个页面表项,其中包含体系结构特定的位,表示:“当CPU处于内核模式时,此页面表项才有效”。

remap_pfn_range 的作用是创建另一个页面表项,使用不同的虚拟地址映射到相同的物理内存页,但该页面表项没有设置那个位。

通常情况下,这是一个不好的想法 :-)


内核在不再需要映射时是否会删除此PTE?这是如何清理的? - sham1810

11

这个机制的核心是页面表内存管理单元:

相关图片1 http://windowsitpro.com/content/content/3686/figure_01.gif

或者这个:

Related image

上面的两张图片都是x86硬件内存MMU的特征,与Linux内核无关。
下面描述了VMAs如何与进程的task_struct相关联: 相关图片 http://image9.360doc.com/DownloadImg/2010/05/0320/3083800_2.gif 相关图片 (来源: slideplayer.com) 在这里查看函数本身:

http://lxr.free-electrons.com/source/mm/memory.c#L1756

物理内存中的数据可以通过内核的PTE来访问,如下所示:
Image result for page protection flags linux kernel
(来源: tldp.org) 但是调用remap_pfn_range()后,将导出一个PTE(用于在用户空间中访问现有的内核内存),具有不同的页面保护标志。进程的VMA内存将被更新为使用此PTE来访问相同的内存-从而最小化通过复制浪费内存的需要。但是内核和用户空间PTE具有不同的属性-它用于控制对物理内存的访问,并且VMA还将在进程级别指定这些属性:
vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP;

“部分与内核的页表重合,这些页表不会为每个进程复制。” 当您说这句话时,您是指内核映射只有一个页表副本,可供所有进程使用吗?您能否详细说明如何实现这一点? - user31986
也许你可以阅读这个链接:http://turkeyland.net/projects/overflow/intro.php 从图片中可以看出,一个进程对应一个页表集合,其基地址将被加载到CR3寄存器中。对于所有那些要在不同进程之间共享的虚拟地址(特别是内核),它们都将具有相同的值,指向同一个物理页面。希望这能澄清问题。 - Peter Teoh
如何持有“mm信号量”? - Adam Miller
这个全局变量是针对每个进程的,但是进程内的多个并发线程可能会获取它,因此需要通过up_read()或down_read()进行锁定。 - Peter Teoh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接