【问题标题】:How remap_pfn_range remaps kernel memory to user space?remap_pfn_range 如何将内核内存重新映射到用户空间?
【发布时间】:2012-02-05 23:31:22
【问题描述】:

remap_pfn_range 函数(用于驱动程序中的mmap 调用)可用于将内核内存映射到用户空间。它是如何完成的?任何人都可以解释精确的步骤吗?内核模式是特权模式 (PM),而用户空间是非特权 (NPM)。在 PM 中,CPU 可以访问所有内存,而在 NPM 中,某些内存受到限制 - CPU 无法访问。当remap_pfn_range 被调用时,这个仅限于 PM 的内存范围现在如何可供用户空间访问?

查看remap_pfn_range 代码有pgprot_t struct。这是与保护映射相关的结构。什么是保护映射?是上面问题的答案吗?

【问题讨论】:

    标签: linux-kernel linux-device-driver kernel-module virtual-address-space


    【解决方案1】:

    真的很简单,内核内存(通常)只是有一个页表条目,其中包含特定于体系结构的位,上面写着:“这个页表条目仅在 CPU 处于内核模式时才有效”。

    remap_pfn_range 所做的是创建另一个页表条目,其虚拟地址与没有设置该位的同一物理内存页不同。

    通常,顺便说一句,这是个坏主意 :-)

    【讨论】:

      【解决方案2】:

      机制的核心是页表MMU:

      Related image1 http://windowsitpro.com/content/content/3686/figure_01.gif

      或者这个:

      上图均为x86硬件内存MMU的特性,与Linux内核无关。

      下面描述了 VMA 是如何链接到进程的 task_struct 的:

      Related image http://image9.360doc.com/DownloadImg/2010/05/0320/3083800_2.gif


      (来源:slideplayer.com

      在这里查看函数本身:

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

      内核可以通过内核的PTE访问物理内存中的数据,如下图:


      (来源:tldp.org

      但是在调用 remap_pfn_range() 之后,派生了一个 PTE(用于现有内核内存,但要在用户空间中访问它)(具有不同的页面保护标志)。进程的 VMA 内存将更新为使用此 PTE 访问相同的内存 - 从而最大限度地减少复制浪费内存的需要。但是内核和用户空间PTE有不同的属性——用来控制对物理内存的访问,VMA也会在进程级别指定属性:

      vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP;

      【讨论】:

      • “其中一部分与内核的页表一致,每个进程都没有重复”当你说你的意思是只有一个用于内核映射的页表副本被使用通过所有流程?您能否详细说明如何做到这一点?
      • 也许读到这个:turkeyland.net/projects/overflow/intro.php,从图中你可以看到一个进程一个页表集,其基地址将被加载到 CR3 寄存器中。对于所有要在不同进程之间共享的虚拟地址(特别是内核),所有这些都将具有指向同一物理页面的相同值。希望澄清。
      • 如何持有“mm 信号量”?
      • 这个全局变量是per-process的,但是进程内的多个并发线程可能会获取到它,因此需要通过up_read()或者down_read()来加锁。
      猜你喜欢
      • 2017-06-28
      • 2014-06-10
      • 2016-03-10
      • 1970-01-01
      • 2017-01-12
      • 2012-11-15
      • 2012-08-02
      • 2012-09-29
      • 2019-05-28
      相关资源
      最近更新 更多