Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the relation between virt_to_phys and the CPU's MMU in the Linux kernel?

I am reading about Linux memory management. I know that

The Linux kernel is responsible for creating and maintaining page tables but employs the CPU’s memory management unit (MMU) to translate the virtual memory accesses of a process into corresponding physical memory accesses.

But, I also know kernel can use some its functions to manage memory such as virt_to_phys(), virt_to_page(), __pa(), ...

Example:

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

used to translate a virtual address to the physical address.

I am very confused about them. Please help to show me the relations between MMU's translation and kernel's translation and distinguish them?

like image 410
Tiktac Avatar asked Apr 17 '15 09:04

Tiktac


2 Answers

In systems with virtual memory the OS kernel is responsible for establishing the mapping between physical and virtual addresses.

However, when the CPU executes instructions that access memory, the CPU performs the translation from the process's virtual address to the physical address that indicates the actual location in memory.

The functions you mentioned can be used inside kernel code to get the translation for virtual to physical addresses for some addresses that are used in kernel code. For example for the x86 target you can see the definition on virt_to_phys in 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);
}

and if you follow the definition of __pa(address) you will see that it ends up calling __phys_addr which is defined as:

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;
}

So you can see the kernel is calculating the physical address from the virtual address using an offset. Depending on the architecture that the code is compiled for the translation will be different. And as the comment for virt_to_phys mentions, this only works for memory in the kernel that is directly mapped or allocated via kmalloc it does not translate arbitrary physical to virtual addresses. That translation relies on looking up the page table mapping.

In either case the actual instructions that execute on the CPU as part of the kernel will still rely on the CPU's MMU to translate from the virtual addresses that they operate on to the physical addresses where the data is actually located in memory.

like image 95
Gabriel Southern Avatar answered Oct 02 '22 17:10

Gabriel Southern


MMU address translation is a hardware(cpu) behavior. The translation must be done as physical address is the valid address that could be used by hardware to access the memory. On the other hand, kernel function like va_to_pa() is used to convert kernel logical address(va) to physical address(pa), which means kernel uses virtual address other than physical address, although it is just constant shift between va and pa.

Kernel instruction and data are in a virtual address, but kernel use physical address to do a lot of thing, such as preparing the page table entry, get dma address for device and soon. So kernel needs functions like va_to_pa().

like image 27
Chris Tsui Avatar answered Oct 02 '22 16:10

Chris Tsui