GNU/Linux >> Tutoriels Linux >  >> Linux

Comprendre la prise en charge des adresses virtuelles 52 bits dans le noyau Arm64

Lorsque le matériel 64 bits est devenu disponible, la nécessité de gérer des espaces d'adressage plus grands (supérieurs à 2 octets) est devenue évidente. Certains fournisseurs proposant désormais des serveurs avec 64 Tio (ou plus) de mémoire, x86_64 et arm64 autorisent désormais l'adressage d'espaces d'adressage supérieurs à 2 octets (disponible avec la prise en charge des adresses 48 bits par défaut).

x86_64 a résolu ces cas d'utilisation en activant la prise en charge des tables de pages à cinq niveaux dans le matériel et le logiciel. Cela permet d'adresser des espaces d'adressage égaux à 2 octets (voir x86 :activation de la pagination à 5 niveaux pour v4.12 pour plus de détails). Il repousse les limites à 128 PiB d'espace d'adressage virtuel et 4 PiB d'espace d'adressage physique.

arm64 a réalisé la même chose en introduisant deux nouvelles extensions d'architecture :ARMv8.2 LVA (Large Virtual Addressing) et ARMv8.2 LPA (Large Physical Addressing). Ceux-ci autorisent 4 PiB d'espace d'adressage virtuel et 4 PiB d'espace d'adressage physique (c'est-à-dire 2 bits chacun, respectivement).

Plus de ressources Linux

  • Aide-mémoire des commandes Linux
  • Aide-mémoire des commandes Linux avancées
  • Cours en ligne gratuit :Présentation technique de RHEL
  • Aide-mémoire sur le réseau Linux
  • Aide-mémoire SELinux
  • Aide-mémoire sur les commandes courantes de Linux
  • Que sont les conteneurs Linux ?
  • Nos derniers articles Linux

Avec les extensions d'architecture ARMv8.2 disponibles dans les nouveaux processeurs arm64, les deux nouvelles extensions matérielles sont désormais prises en charge dans les logiciels open source.

À partir de la version 5.4 du noyau Linux, la prise en charge de l'adresse virtuelle (VA) et de l'adresse physique (PA) 52 bits (large) a été introduite pour l'architecture arm64. Bien que la documentation du noyau décrive ces fonctionnalités et leur impact sur les nouveaux noyaux exécutés sur des processeurs plus anciens (qui ne prennent pas en charge l'extension VA 52 bits dans le matériel) et les processeurs plus récents (qui prennent en charge les extensions VA 52 bits dans le matériel), il peut être complexe pour les utilisateurs moyens de les comprendre et comment ils peuvent "opter" pour recevoir des VA à partir d'un espace 52 bits.

Par conséquent, je vais présenter ces concepts relativement nouveaux dans cet article :

  1. Comment la disposition de la mémoire du noyau a été "inversée" pour Arm64 après l'ajout de la prise en charge de ces fonctionnalités
  2. L'impact sur les applications de l'espace utilisateur, en particulier celles qui fournissent une prise en charge du débogage (par exemple, kexec-tools, makedumpfile et crash-utility)
  3. Comment les applications de l'espace utilisateur peuvent-elles "opter" pour recevoir des VA à partir d'un espace 52 bits en spécifiant un paramètre mmap hint supérieur à 48 bits

Extensions LVA et LPA de l'architecture ARMv8.2

L'architecture ARMv8.2 fournit deux extensions importantes :Large Virtual Addressing (LVA) et Large Physical Addressing (LPA).

ARMv8.2-LVA prend en charge un espace VA plus grand pour chaque registre de base de table de traduction jusqu'à 52 bits lors de l'utilisation du granule de traduction de 64 Ko.

ARMv8.2-LPA permet :

  • Une adresse physique intermédiaire (IPA) plus grande et un espace PA pouvant atteindre 52 bits lors de l'utilisation du granule de traduction de 64 Ko
  • Une taille de bloc de niveau 1 où le bloc couvre une plage d'adresses de 4 To pour le granule de traduction de 64 Ko si la mise en œuvre prend en charge 52 bits de PA

Notez que ces fonctionnalités ne sont prises en charge que dans l'état AArch64.

Actuellement, les processeurs Arm64 Cortex-A suivants prennent en charge les extensions ARMv8.2 :

  • Cortex-A55
  • Cortex-A75
  • Cortex-A76

Pour plus de détails, consultez le manuel de référence de l'architecture Armv8.

Disposition de la mémoire du noyau sur Arm64

Avec l'extension ARMv8.2 ajoutant la prise en charge de l'espace LVA (qui n'est disponible que lors de l'exécution avec une taille de page de 64 Ko), le nombre de descripteurs est augmenté dans le premier niveau de traduction.

Les adresses utilisateur ont les bits 63:48 définis sur 0, tandis que les adresses du noyau ont les mêmes bits définis sur 1. La sélection TTBRx est donnée par le bit 63 de l'adresse virtuelle. Le swapper_pg_dir contient uniquement des mappages de noyau (globaux), tandis que l'utilisateur pgd contient uniquement des mappages utilisateur (non globaux). Le swapper_pg_dir l'adresse est écrite dans TTBR1 et jamais écrite dans TTBR0.

Disposition de la mémoire Linux AArch64 avec des pages de 64 Ko plus trois niveaux (52 bits avec prise en charge matérielle) :

  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]

Recherche de table de traduction avec des pages de 4 Ko :

  +--------+--------+--------+--------+--------+--------+--------+--------+
  |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

Recherche dans la table de traduction avec des pages de 64 Ko :

  +--------+--------+--------+--------+--------+--------+--------+--------+
  |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

Prise en charge VA 52 bits dans le noyau

Étant donné que les nouveaux noyaux prenant en charge LVA devraient bien fonctionner sur les anciens processeurs (qui ne prennent pas en charge l'extension LVA dans le matériel) et les nouveaux processeurs (qui prennent en charge l'extension LVA dans le matériel), l'approche de conception choisie consiste à avoir un seul binaire qui prend en charge 52 bits (et doit pouvoir revenir à 48 bits au début du démarrage si la fonctionnalité matérielle n'est pas présente). Autrement dit, le VMEMMAP doit être suffisamment grand pour les VA 52 bits et doit également être suffisamment grand pour accueillir un PAGE_OFFSET fixe .

Cette approche de conception nécessite que le noyau prenne en charge les variables suivantes pour le nouvel espace d'adressage virtuel :

VA_BITS         constant        the *maximum* VA space size

vabits_actual   variable        the *actual* VA space size

Ainsi, alors que VA_BITS indique la taille maximale de l'espace VA, l'espace VA réel pris en charge (en fonction du commutateur effectué au démarrage) est indiqué par vabits_actual .

Inverser la disposition de la mémoire du noyau

L'approche de conception consistant à conserver un seul noyau binaire nécessite que le noyau .text se trouve dans les adresses les plus élevées, de sorte qu'elles soient invariantes pour les VA 48/52 bits. Étant donné que le shadow Kernel Address Sanitizer (KASAN) représente une fraction de l'ensemble de l'espace VA du noyau, la fin du shadow KASAN doit également se trouver dans la moitié supérieure de l'espace VA du noyau pour 48 et 52 bits. (Passage de 48 bits à 52 bits, la fin de l'ombre KASAN est invariante et dépendante de ~0UL , tandis que l'adresse de départ "augmentera" vers les adresses inférieures).

Pour optimiser phys_to_virt() et virt_to_phys() , le PAGE_OFFSET est maintenu constant à 0xFFF0000000000000 (correspondant à 52 bits), cela évite la nécessité d'une lecture de variable supplémentaire. Le physvirt et vmemmap les décalages sont calculés au début du démarrage pour activer cette logique.

Considérez la conversion d'espace d'adressage RAM physique et virtuelle suivante :

/*
 * 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

Impact sur les applications de l'espace utilisateur utilisées pour déboguer le noyau

Plusieurs applications de l'espace utilisateur sont utilisées pour déboguer les noyaux en cours d'exécution/en direct ou analyser le vidage vmcore d'un système en panne (par exemple, pour déterminer la cause première du plantage du noyau) :kexec-tools, makedumpfile et crash-utility.

Lorsque ceux-ci sont utilisés pour déboguer le noyau Arm64, il y a également un impact sur eux car la carte mémoire du noyau Arm64 est "basculée". Ces applications doivent également effectuer un parcours de table de traduction pour déterminer une adresse physique correspondant à une adresse virtuelle (similaire à la façon dont cela se fait dans le noyau).

En conséquence, les applications de l'espace utilisateur doivent être modifiées car elles sont cassées en amont après l'introduction du "flip" dans la carte mémoire du noyau.

J'ai proposé des correctifs dans les trois applications de l'espace utilisateur concernées ; alors que certains ont été acceptés en amont, d'autres sont toujours en attente :

  • Correction proposée en amont de makedumpfile
  • Correction proposée en amont de kexec-tools
  • Correction acceptée dans crash-utility

À moins que ces modifications ne soient apportées aux applications de l'espace utilisateur, elles resteront brisées pour le débogage des noyaux en cours d'exécution/en direct ou l'analyse du vidage vmcore à partir d'un système en panne.

VA 52 bits en espace utilisateur

Pour maintenir la compatibilité avec les applications de l'espace utilisateur qui reposent sur la taille maximale de l'espace VA ARMv8.0 de 48 bits, le noyau renverra, par défaut, des adresses virtuelles à l'espace utilisateur à partir d'une plage de 48 bits.

Les applications de l'espace utilisateur peuvent "opter" pour recevoir des VA à partir d'un espace 52 bits en spécifiant un paramètre d'indication mmap supérieur à 48 bits.

Par exemple :

.mmap_high_addr.c
----

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

Il est également possible de créer un noyau de débogage qui renvoie des adresses à partir d'un espace 52 bits en activant les options de configuration du noyau suivantes :

   CONFIG_EXPERT=y && CONFIG_ARM64_FORCE_52BIT=y

Notez que cette option est uniquement destinée au débogage des applications et ne doit pas être utilisé en production.

Conclusions

Pour résumer :

  1. À partir de la version 5.14 du noyau Linux, les nouvelles extensions matérielles Armv8.2 LVA et LPA sont désormais bien prises en charge dans le noyau Linux.
  2. Les applications de l'espace utilisateur comme kexec-tools et makedumpfile utilisées pour déboguer le noyau sont cassées actuellement et en attente d'acceptation des correctifs en amont.
  3. Les anciennes applications de l'espace utilisateur qui s'appuient sur le noyau Arm64 en lui fournissant une VA 48 bits continueront de fonctionner telles quelles, tandis que les nouvelles applications de l'espace utilisateur peuvent "opter" pour recevoir des VA à partir d'un espace 52 bits en spécifiant un paramètre d'indication mmap qui est supérieur à 48 bits.

Cet article s'appuie sur la disposition de la mémoire sur AArch64 Linux et la documentation du noyau Linux v5.9.12. Les deux sont sous licence GPLv2.0.


Linux
  1. Trouver l'ordinateur sur un réseau LAN ?

  2. Le statut du support Hidpi dans Xfce ?

  3. Personnalisation du noyau (arm64) à l'aide d'Ubuntu 20.04 Lts sur un Raspberry Pi 4 ?

  4. Présentation de la version effective du noyau de Ksplice

  5. Comment vérifier HZ dans le terminal?

Ansible vs Kubernetes :comprendre les différences

Comment vérifier la version du noyau sous Linux

Comment trouver l'adresse IP d'une machine virtuelle KVM

Comprendre la commande time sous Linux

Pourquoi le noyau est-il mappé sur le même espace d'adressage que les processus ?

Quelle est l'utilité d'avoir une partie noyau dans l'espace de mémoire virtuelle des processus Linux ?