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

Tik*_*tac 15 linux memory cpu cpu-architecture linux-kernel

我正在阅读有关Linux内存管理的内容.我知道

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

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

例:

static inline unsigned long virt_to_phys(volatile void *address)
{
    return __pa(address);
}
Run Code Online (Sandbox Code Playgroud)

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

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

Gab*_*ern 11

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

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

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

/**
 *  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);
}
Run Code Online (Sandbox Code Playgroud)

如果你按照你的定义__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;
}
Run Code Online (Sandbox Code Playgroud)

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

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