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?
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.
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()
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With