【问题标题】:What is the relation between virt_to_phys and the CPU's MMU in the Linux kernel?Linux内核中virt_to_phys和CPU的MMU是什么关系?
【发布时间】:2015-06-24 01:42:48
【问题描述】:

我正在阅读有关 Linux 内存管理的信息。我知道

Linux 内核负责创建和维护页表,但使用 CPU 的内存管理单元 (MMU) 将进程的虚拟内存访问转换为相应的物理内存访问。

但是,我也知道内核可以使用它的一些函数来管理内存,例如virt_to_phys()virt_to_page()__pa(),...

例子:

static inline unsigned long virt_to_phys(volatile void *address)
{
    return __pa(address);
}

用于将虚拟地址转换为物理地址。

我对他们很困惑。请帮我看看MMU翻译和内核翻译之间的关系并区分它们?

【问题讨论】:

    标签: linux memory linux-kernel cpu cpu-architecture


    【解决方案1】:

    据我了解,在内核端对物理地址的任何使用都仅供参考,很可能只是为了任何实际的更改/移动而被翻译回来。造成这种情况的原因有很多,一个是内存可能会被重新分配用于其他目的,IE 将数据从物理内存移动到页面文件(磁盘内存),或者如果空间更大,则在物理内存分配内移动需要该数据。因此,如果内核只是在不告诉你的情况下移动它,那么使用物理地址是不好的。 Here is an interesting bit on the subject. And a lot more detail here.

    【讨论】:

    • 关于 Linux 内核中内存的最全面的指南可能是here (PDF)。或者,如果您愿意 - 在HTML
    • @SamProtsenko 这绝对有你想知道的一切,一直到门级。第 3 部分(虚拟内存)稍微涉及到这一点,但没有深入探讨原因和 linux 细节。
    【解决方案2】:

    virt_to_phys() 和其他函数实际上利用了页表的不同属性,如 PAGE_OFFSET 等。这些页表是由内核的内存管理子系统创建的,但它们又利用 MMU 硬件进行读/写主内存中的物理页。

    您还可以参考不同的可用文档,其中之一是: https://www.kernel.org/doc/gorman/html/understand/understand006.html

    【讨论】:

      【解决方案3】:

      这是要点。

      1.) 内核和其他软件在虚拟地址方面工作。每次查找对应物理地址的硬件页表查找(或TLB fetch)都是需要的。

      2.) 在启动时内核建立虚拟映射:为简单起见,我会说它将地址 0x0 .. n 的内存映射到 0xc0000000 .. 0xc0000000 + n(所谓的低内存)。

      3.) 已建立的映射是静态的。对于低内存地址,以下函数是合适的:

      virt_to_page(), __pa(), ...
      

      意思是

      virtual address = physical address + some offset
      

      因此,您可以轻松获取内核代码中相应低内存页的 phys/virt 地址(MMU 使用通用机制,即每次都进行页表遍历)。这个偏移量只是惯例,仅此而已。

      【讨论】:

        【解决方案4】:

        在具有虚拟内存的系统中,操作系统内核负责建立物理地址和虚拟地址之间的映射。

        但是,当 CPU 执行访问内存的指令时,CPU 会执行从进程的虚拟地址到指示内存中实际位置的物理地址的转换。

        您提到的函数可以在内核代码中使用,以获取内核代码中使用的某些地址的虚拟地址到物理地址的转换。例如对于 x86 目标,您可以在io.h 中查看virt_to_phys 上的定义:

        /**
         *  virt_to_phys    -   map virtual addresses to physical
         *  @address: address to remap
         *
         *  The returned physical address is the physical (CPU) mapping for
         *  the memory address given. It is only valid to use this function on
         *  addresses directly mapped or allocated via kmalloc.
         *
         *  This function does not give bus mappings for DMA transfers. In
         *  almost all conceivable cases a device driver should not be using
         *  this function
         */
        
        static inline phys_addr_t virt_to_phys(volatile void *address)
        {
            return __pa(address);
        }
        

        如果您遵循__pa(address) 的定义,您会看到它最终调用__phys_addr,其定义为:

        unsigned long __phys_addr(unsigned long x)
        {
            if (x >= __START_KERNEL_map) {
                x -= __START_KERNEL_map;
                VIRTUAL_BUG_ON(x >= KERNEL_IMAGE_SIZE);
                x += phys_base;
            } else {
                VIRTUAL_BUG_ON(x < PAGE_OFFSET);
                x -= PAGE_OFFSET;
                VIRTUAL_BUG_ON(!phys_addr_valid(x));
            }
            return x;
        }
        

        因此您可以看到内核正在使用偏移量从虚拟地址计算物理地址。根据为翻译而编译的代码的体系结构会有所不同。正如virt_to_phys 的评论所提到的,这仅适用于内核中通过 kmalloc 直接映射或分配的内存,它不会将任意物理地址转换为虚拟地址。该翻译依赖于查找页表映射。

        在任何一种情况下,作为内核的一部分在 CPU 上执行的实际指令仍将依赖 CPU 的 MMU 将它们操作的虚拟地址转换为数据实际位于内存中的物理地址。

        【讨论】:

        • 您好 Gabriel 先生,我了解内核负责设置页表和物理地址和虚拟地址之间的映射,这是软件方面的,而在硬件方面,CPU 将加载这些指令,MMU 从virtual to phys to access memory,但我还不知道内核的翻译,你能详细解释一下内核是如何工作的吗?比如调用 virt_to_phys() 后,内核可以立即获取物理地址,对吗?这个phys地址是不是和MMU翻译后的地址类似?
        • @Sam 我从内核代码中添加了一些细节来帮助解释你提到的函数是如何工作的。
        • 嗨 Gabriel,可以说内核只负责创建和维护页表,这意味着一些函数只被内核在引导或创建进程阶段以创建页表时使用,内核使用他们知道并配置每个虚拟地址区域将映射到哪个物理地址区域?内核的identify-mapped段中的所有地址都将通过__pa()函数映射到phys地址,而其他区域的所有地址都将映射到其他phys区域(因为映射段将通过kmap()映射到phys地址)?我的理解有什么错误吗?
        【解决方案5】:

        MMU 地址转换是一种硬件(cpu)行为。必须进行转换,因为物理地址是硬件可以用来访问内存的有效地址。另一方面,像va_to_pa()这样的内核函数用于将内核逻辑地址(va)转换为物理地址(pa),这意味着内核使用物理地址以外的虚拟地址,尽管它只是在va和pa之间不断移动。

        内核指令和数据都在一个虚拟地址中,但是内核使用物理地址做很多事情,比如准备页表条目,为设备获取dma地址等等。所以内核需要像va_to_pa()这样的函数。

        【讨论】:

        • 感谢您的回答!我想深入了解记忆,但我觉得这很难......
        • 我认为最好的方法是了解特定拱门的底层硬件机制(尽管大多数 CPU 具有相同的概念),例如 TLBring mode(privilege)virtual address space
        【解决方案6】:

        您可以阅读Understanding Linux Kernel 一书以获取更多信息。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-05-01
          • 2012-07-21
          • 2020-07-17
          • 1970-01-01
          • 1970-01-01
          • 2018-06-10
          • 2017-03-02
          • 1970-01-01
          相关资源
          最近更新 更多