在具有虚拟内存的系统中,OS内核负责建立物理地址和虚拟地址之间的映射。
然而,当CPU执行存取存储器的指令,CPU执行从进程的虚拟地址,表示在内存中的实际位置的物理地址翻译。
您提到的函数可以在内核代码中使用,以获得内核代码中使用的某些地址的虚拟地址到物理地址的转换。例如,对于x86的目标,你可以看到virt_to_phys的定义io.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);
}
,如果你遵循的__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从它们操作的虚拟地址转换为数据实际位于内存中的物理地址。