GNU/Linux >> Tutoriales Linux >  >> Linux

Comprensión de la compatibilidad con direcciones virtuales de 52 bits en el kernel Arm64

Después de que el hardware de 64 bits estuvo disponible, se hizo evidente la necesidad de manejar espacios de direcciones más grandes (más de 2 bytes). Con algunos proveedores que ahora ofrecen servidores con 64 TiB (o más) de memoria, x86_64 y arm64 ahora permiten direccionar espacios de direcciones de más de 2 bytes (disponible con el soporte de dirección predeterminado de 48 bits).

x86_64 abordó estos casos de uso al habilitar la compatibilidad con tablas de páginas de cinco niveles tanto en hardware como en software. Esto permite direccionar espacios de direcciones iguales a 2 bytes (ver x86:habilitación de paginación de 5 niveles para v4.12 para más detalles). Supera los límites a 128PiB de espacio de direcciones virtuales y 4PiB de espacio de direcciones físicas.

arm64 logró lo mismo al presentar dos nuevas extensiones de arquitectura:ARMv8.2 LVA (direccionamiento virtual grande) y ARMv8.2 LPA (direccionamiento físico grande). Estos permiten 4 PiB de espacio de direcciones virtuales y 4 PiB de espacios de direcciones físicas (es decir, 2 bits cada uno, respectivamente).

Más recursos de Linux

  • Hoja de trucos de los comandos de Linux
  • Hoja de trucos de comandos avanzados de Linux
  • Curso en línea gratuito:Descripción general técnica de RHEL
  • Hoja de trucos de red de Linux
  • Hoja de trucos de SELinux
  • Hoja de trucos de los comandos comunes de Linux
  • ¿Qué son los contenedores de Linux?
  • Nuestros últimos artículos sobre Linux

Con las extensiones de arquitectura ARMv8.2 disponibles en las nuevas CPU arm64, las dos nuevas extensiones de hardware ahora son compatibles con el software de código abierto.

A partir de la versión 5.4 del kernel de Linux, se introdujo la compatibilidad con la dirección virtual (VA) y la dirección física (PA) de 52 bits (grandes) para la arquitectura arm64. Aunque la documentación del núcleo describe estas funciones y cómo afectan a los nuevos núcleos que se ejecutan en CPU más antiguas (que no admiten la extensión VA de 52 bits en hardware) y CPU más nuevas (que admiten extensiones VA de 52 bits en hardware), puede ser complejo para que los usuarios promedio los entiendan y cómo pueden "optar por participar" para recibir VA desde un espacio de 52 bits.

Por lo tanto, presentaré estos conceptos relativamente nuevos en este artículo:

  1. Cómo se "cambió" el diseño de la memoria del kernel para Arm64 después de que se agregó la compatibilidad con estas funciones
  2. El impacto en las aplicaciones del espacio de usuario, especialmente las que brindan compatibilidad con la depuración (por ejemplo, herramientas kexec, makedumpfile y utilidad de bloqueo)
  3. Cómo las aplicaciones del espacio de usuario pueden "optar" por recibir VA desde un espacio de 52 bits especificando un parámetro de sugerencia mmap que es mayor a 48 bits

Arquitectura ARMv8.2 LVA y extensiones LPA

La arquitectura ARMv8.2 proporciona dos extensiones importantes:direccionamiento virtual grande (LVA) y direccionamiento físico grande (LPA).

ARMv8.2-LVA admite un espacio VA más grande para cada registro base de la tabla de traducción de hasta 52 bits cuando se usa el gránulo de traducción de 64 KB.

ARMv8.2-LPA permite:

  • Una dirección física intermedia (IPA) más grande y un espacio PA de hasta 52 bits cuando se usa el gránulo de traducción de 64 KB
  • Un tamaño de bloque de nivel 1 donde el bloque cubre un rango de direcciones de 4 TB para el gránulo de traducción de 64 KB si la implementación admite 52 bits de PA

Tenga en cuenta que estas funciones solo se admiten en el estado AArch64.

Actualmente, los siguientes procesadores Arm64 Cortex-A admiten extensiones ARMv8.2:

  • Corteza-A55
  • Corteza-A75
  • Corteza-A76

Para obtener más detalles, consulte el Manual de referencia de la arquitectura Armv8.

Disposición de la memoria del kernel en Arm64

Con la extensión ARMv8.2 que agrega soporte para el espacio LVA (que solo está disponible cuando se ejecuta con un tamaño de página de 64 KB), la cantidad de descriptores se amplía en el primer nivel de traducción.

Las direcciones de usuario tienen los bits 63:48 configurados en 0, mientras que las direcciones del kernel tienen los mismos bits configurados en 1. La selección de TTBRx está dada por el bit 63 de la dirección virtual. El swapper_pg_dir contiene solo asignaciones del kernel (globales), mientras que el usuario pgd contiene solo asignaciones de usuario (no globales). El swapper_pg_dir la dirección se escribe en TTBR1 y nunca se escribe en TTBR0.

Diseño de memoria AArch64 Linux con páginas de 64 KB más tres niveles (52 bits con soporte de hardware):

  Start                 End                     Size            Use
  -----------------------------------------------------------------------
  0000000000000000      000fffffffffffff           4PB          user
  fff0000000000000      fff7ffffffffffff           2PB          kernel logical memory map
  fff8000000000000      fffd9fffffffffff        1440TB          [gap]
  fffda00000000000      ffff9fffffffffff         512TB          kasan shadow region
  ffffa00000000000      ffffa00007ffffff         128MB          bpf jit region
  ffffa00008000000      ffffa0000fffffff         128MB          modules
  ffffa00010000000      fffff81ffffeffff         ~88TB          vmalloc
  fffff81fffff0000      fffffc1ffe58ffff          ~3TB          [guard region]
  fffffc1ffe590000      fffffc1ffe9fffff        4544KB          fixed mappings
  fffffc1ffea00000      fffffc1ffebfffff           2MB          [guard region]
  fffffc1ffec00000      fffffc1fffbfffff          16MB          PCI I/O space
  fffffc1fffc00000      fffffc1fffdfffff           2MB          [guard region]
  fffffc1fffe00000      ffffffffffdfffff        3968GB          vmemmap
  ffffffffffe00000      ffffffffffffffff           2MB          [guard region]

Búsqueda de tabla de traducción con páginas de 4 KB:

  +--------+--------+--------+--------+--------+--------+--------+--------+
  |63    56|55    48|47    40|39    32|31    24|23    16|15     8|7      0|
  +--------+--------+--------+--------+--------+--------+--------+--------+
   |                 |         |         |         |         |
   |                 |         |         |         |         v
   |                 |         |         |         |   [11:0]  in-page offset
   |                 |         |         |         +-> [20:12] L3 index
   |                 |         |         +-----------> [29:21] L2 index
   |                 |         +---------------------> [38:30] L1 index
   |                 +-------------------------------> [47:39] L0 index
   +-------------------------------------------------> [63] TTBR0/1

Búsqueda de tabla de traducción con páginas de 64 KB:

  +--------+--------+--------+--------+--------+--------+--------+--------+
  |63    56|55    48|47    40|39    32|31    24|23    16|15     8|7      0|
  +--------+--------+--------+--------+--------+--------+--------+--------+
   |                 |    |               |              |
   |                 |    |               |              v
   |                 |    |               |            [15:0]  in-page offset
   |                 |    |               +----------> [28:16] L3 index
   |                 |    +--------------------------> [41:29] L2 index
   |                 +-------------------------------> [47:42] L1 index (48-bit)
   |                                                   [51:42] L1 index (52-bit)
   +-------------------------------------------------> [63] TTBR0/1

Soporte de VA de 52 bits en el kernel

Dado que los núcleos más nuevos con compatibilidad con LVA deberían funcionar bien en CPU más antiguas (que no admiten la extensión LVA en el hardware) y las CPU más nuevas (que admiten la extensión LVA en el hardware), el enfoque de diseño elegido es tener un solo binario que admita 52 bits (y debe poder retroceder a 48 bits al inicio temprano si la función de hardware no está presente). Es decir, el VMEMMAP debe tener un tamaño lo suficientemente grande para dispositivos virtuales de 52 bits y también debe tener un tamaño lo suficientemente grande para acomodar un PAGE_OFFSET fijo .

Este enfoque de diseño requiere que el kernel admita las siguientes variables para el nuevo espacio de direcciones virtuales:

VA_BITS         constant        the *maximum* VA space size

vabits_actual   variable        the *actual* VA space size

Entonces, mientras VA_BITS indica el tamaño máximo del espacio VA, el espacio VA real admitido (según el cambio realizado en el momento del arranque) se indica mediante vabits_actual .

Volteando el diseño de la memoria del kernel

El enfoque de diseño de mantener un solo kernel binario requiere que el kernel .text esté en las direcciones más altas, de modo que no varíen con los VA de 48/52 bits. Debido a que la sombra de Kernel Address Sanitizer (KASAN) es una fracción de todo el espacio VA del kernel, el final de la sombra KASAN también debe estar en la mitad superior del espacio VA del kernel para 48 y 52 bits. (Al cambiar de 48 bits a 52 bits, el final de la sombra KASAN es invariable y depende de ~0UL , mientras que la dirección de inicio "crecerá" hacia las direcciones inferiores).

Para optimizar phys_to_virt() y virt_to_phys() , el PAGE_OFFSET se mantiene constante en 0xFFF0000000000000 (correspondiente a 52 bits), esto evita la necesidad de una lectura de variable adicional. El physvirt y vmemmap las compensaciones se calculan en el inicio temprano para habilitar esta lógica.

Considere la siguiente conversión de espacio de direcciones de RAM física frente a virtual:

/*
 * The linear kernel range starts at the bottom of the virtual address
 * space. Testing the top bit for the start of the region is a
 * sufficient check and avoids having to worry about the tag.
 */

#define virt_to_phys(addr) ({                                   \
        if (!(((u64)addr) & BIT(vabits_actual - 1)))            \
                (((addr) & ~PAGE_OFFSET) + PHYS_OFFSET)
})

#define phys_to_virt(addr) ((unsigned long)((addr) - PHYS_OFFSET) | PAGE_OFFSET)

where:
 PAGE_OFFSET - the virtual address of the start of the linear map, at the
                start of the TTBR1 address space,
 PHYS_OFFSET - the physical address of the start of memory, and
 vabits_actual - the *actual* VA space size

Impacto en las aplicaciones del espacio de usuario utilizadas para depurar el kernel

Se utilizan varias aplicaciones de espacio de usuario para depurar kernels activos/en ejecución o analizar el volcado de vmcore de un sistema bloqueado (por ejemplo, para determinar la causa raíz del bloqueo del kernel):herramientas kexec, makedumpfile y crash-utility.

Cuando se utilizan para depurar el kernel de Arm64, también tienen un impacto debido a que el mapa de memoria del kernel de Arm64 se "invierte". Estas aplicaciones también necesitan realizar un recorrido por la tabla de traducción para determinar una dirección física correspondiente a una dirección virtual (similar a cómo se hace en el kernel).

En consecuencia, las aplicaciones del espacio de usuario deben modificarse ya que se rompen aguas arriba después de que se introdujo el "cambio" en el mapa de memoria del kernel.

He propuesto correcciones en las tres aplicaciones de espacio de usuario afectadas; mientras que algunos han sido aceptados aguas arriba, otros aún están pendientes:

  • Propuesta de corrección upstream de makedumpfile
  • Corrección ascendente propuesta de herramientas kexec
  • Corrección aceptada en la utilidad de bloqueo

A menos que estos cambios se realicen en las aplicaciones del espacio de usuario, permanecerán dañados para depurar kernels activos o en ejecución o analizar el volcado de vmcore de un sistema bloqueado.

Vas de espacio de usuario de 52 bits

Para mantener la compatibilidad con las aplicaciones del espacio de usuario que se basan en el tamaño máximo de 48 bits del espacio VA de ARMv8.0, el kernel, de forma predeterminada, devolverá las direcciones virtuales al espacio de usuario desde un rango de 48 bits.

Las aplicaciones del espacio de usuario pueden "suscribirse" para recibir VA desde un espacio de 52 bits especificando un parámetro de sugerencia mmap mayor de 48 bits.

Por ejemplo:

.mmap_high_addr.c
----

   maybe_high_address = mmap(~0UL, size, prot, flags,...);

También es posible crear un kernel de depuración que devuelva direcciones desde un espacio de 52 bits habilitando las siguientes opciones de configuración del kernel:

   CONFIG_EXPERT=y && CONFIG_ARM64_FORCE_52BIT=y

Tenga en cuenta que esta opción solo está diseñada para depurar aplicaciones y no utilizarse en producción.

Conclusiones

Para resumir:

  1. A partir de la versión 5.14 del kernel de Linux, las nuevas extensiones de hardware Armv8.2 LVA y LPA ahora son compatibles con el kernel de Linux.
  2. Las aplicaciones de espacio de usuario como kexec-tools y makedumpfile utilizadas para depurar el kernel están rotas ahora mismo y en espera de la aceptación de las correcciones anteriores.
  3. Las aplicaciones de espacio de usuario heredadas que se basan en el kernel Arm64 que le proporciona un VA de 48 bits seguirán funcionando tal como están, mientras que las aplicaciones de espacio de usuario más nuevas pueden "optar" por recibir VA desde un espacio de 52 bits especificando un parámetro de sugerencia de mmap. que es más grande que 48 bits.

Este artículo se basa en el diseño de memoria en AArch64 Linux y en la documentación del kernel de Linux v5.9.12. Ambos tienen licencia GPLv2.0.


Linux
  1. El kernel de Linux:las 5 principales innovaciones

  2. El ciclo de vida de las pruebas del kernel de Linux

  3. Linux:¿qué implica el diseño de la memoria del kernel virtual en Dmesg?

  4. ¿Personalizar el kernel (arm64) usando Ubuntu 20.04 Lts en una Raspberry Pi 4?

  5. Comprensión de la versión efectiva del kernel de Ksplice

Ansible vs Kubernetes:comprensión de las diferencias

Cómo verificar la versión del kernel en Linux

Cómo encontrar la dirección IP de una máquina virtual KVM

Entendiendo el comando time en Linux

¿Cómo se agrega nuevo soporte de hardware al kernel de Linux?

¿Cómo sabe la CPU qué dirección física está asignada a qué dirección virtual?