¿Cuál es la relación entre virt_to_phys y la MMU de la CPU en el kernel de Linux?
memory linux-kernel (6)
Estoy leyendo sobre la administración de memoria de Linux. Yo sé eso
El kernel de Linux es responsable de crear y mantener las tablas de páginas, pero emplea la unidad de administración de memoria (MMU) de la CPU para traducir los accesos de memoria virtual de un proceso en los correspondientes accesos de memoria física.
Pero, también sé que kernel puede usar algunas de sus funciones para administrar memoria como virt_to_phys()
, virt_to_page()
, __pa()
, ...
Ejemplo:
static inline unsigned long virt_to_phys(volatile void *address)
{
return __pa(address);
}
usado para traducir una dirección virtual a la dirección física.
Estoy muy confundido acerca de ellos. Por favor, ayúdenme a mostrarme las relaciones entre la traducción de MMU y la traducción de Kernel y distinguirlas?
Aquí están los puntos.
1.) Kernel y otros soft works en términos de direcciones virtuales. Cada vez que busca la dirección de hardware física correspondiente, busca tablas (o búsqueda de TLB).
2.) En el momento del arranque, el kernel establece la asignación virtual: por simplicidad diré que mapea la memoria en las direcciones 0x0 .. n a 0xc0000000 .. 0xc0000000 + n (llamada baja memoria).
3.) El mapeo establecido es estático. Para direcciones lowmem, las siguientes funciones son adecuadas:
virt_to_page(), __pa(), ...
Esto significa que
virtual address = physical address + some offset
Por lo tanto, puede obtener fácilmente la dirección phys / virt para la correspondiente página lowmem en el código kernel (MMU usa mecanismos genéricos, es decir, la tabla de páginas camina siempre). Esta compensación es solo una convención, nada más.
El virt_to_phys () y otros realmente hacen uso de diferentes atributos de tablas de página, como PAGE_OFFSET, etc. Estas tablas de página son creadas por el subsistema de administración de memoria del kernel, pero a su vez hacen uso del hardware MMU para leer / escribir una página física en la memoria principal.
También puede consultar diferentes documentos disponibles, uno de ellos es: https://www.kernel.org/doc/gorman/html/understand/understand006.html
Según tengo entendido, cualquier uso de la dirección física en el lado del kernel es simplemente como referencia y lo más probable es que solo se traduzca de vuelta por cualquier cambio / movimiento real. Hay una serie de razones para eso, una es que la memoria puede reasignarse para otro fin, es decir, mover los datos de la memoria física al archivo de página (memoria en el disco) o moverse dentro de la asignación de memoria física si hay más espacio es necesario para esa información. Por lo tanto, no sería bueno usar la dirección física si el kernel simplemente va a moverla sin decírselo. Aquí hay un poco interesante sobre el tema. Y mucho más detalle aquí.
La traducción de direcciones MMU es un comportamiento de hardware (CPU). La traducción debe hacerse como una dirección física es la dirección válida que podría ser utilizada por el hardware para acceder a la memoria. Por otro lado, la función kernel como va_to_pa()
se usa para convertir la dirección lógica del kernel (va) en dirección física (pa), lo que significa que kernel utiliza una dirección virtual distinta a la dirección física, aunque solo es un cambio constante entre va y pa.
Las instrucciones y los datos del kernel están en una dirección virtual, pero el kernel usa la dirección física para hacer muchas cosas, como preparar la entrada de la tabla de páginas, obtener la dirección dma para el dispositivo y pronto. Entonces kernel necesita funciones como va_to_pa()
.
En sistemas con memoria virtual, el núcleo del sistema operativo es responsable de establecer la asignación entre direcciones físicas y virtuales.
Sin embargo, cuando la CPU ejecuta instrucciones que acceden a la memoria, la CPU realiza la traducción desde la dirección virtual del proceso a la dirección física que indica la ubicación real en la memoria.
Las funciones que mencionó se pueden usar dentro del código del kernel para obtener la traducción de direcciones virtuales a físicas para algunas direcciones que se usan en el código del kernel. Por ejemplo, para el objetivo x86, puede ver la definición en virt_to_phys
en 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);
}
y si sigues la definición de __pa(address)
verás que termina llamando a __phys_addr
que se define como:
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;
}
Entonces puede ver que el núcleo está calculando la dirección física desde la dirección virtual usando un desplazamiento. Dependiendo de la arquitectura que el código se compila para la traducción será diferente. Y como menciona el comentario de virt_to_phys
, esto solo funciona para la memoria en el kernel que se mapea o se asigna directamente a través de kmalloc, no traduce direcciones físicas a virtuales arbitrarias. Esa traducción se basa en buscar el mapeo de la tabla de la página.
En cualquier caso, las instrucciones reales que se ejecutan en la CPU como parte del núcleo seguirán dependiendo de la MMU de la CPU para traducir desde las direcciones virtuales en las que operan a las direcciones físicas donde los datos se encuentran realmente en la memoria.
Puede leer Understanding Linux Kernel book para obtener más información.