virt_to_phys和Linux内核中CPU的MMU之间有什么关系?

时间:2015-04-17 09:23:41

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

我正在阅读有关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翻译与内核翻译之间的关系并区分它们?

6 个答案:

答案 0 :(得分:10)

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

但是,当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从其操作的虚拟地址转换为数据实际位于内存中的物理地址。 / p>

答案 1 :(得分:2)

您可以阅读了解Linux内核本书以获取更多信息。

答案 2 :(得分:1)

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

答案 3 :(得分:1)

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

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

答案 4 :(得分:1)

以下是要点。

1。)内核和其他软件在虚拟地址方面的作用。每次查找相应的物理地址硬件页表都需要查找(或TLB获取)。

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

3。)已建立的映射是静态的。对于lowmem地址,以下函数适用:

virt_to_page(), __pa(), ...

这意味着

virtual address = physical address + some offset

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

答案 5 :(得分:1)

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

内核指令和数据都在虚拟地址中,但是内核使用物理地址做很多事情,比如准备页表项,很快得到设备的dma地址。所以内核需要va_to_pa()等函数。