GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Verstehen der Unterstützung für virtuelle 52-Bit-Adressen im Arm64-Kernel

Nachdem 64-Bit-Hardware verfügbar wurde, wurde die Notwendigkeit, größere Adressräume (mehr als 2 Byte) zu handhaben, offensichtlich. Da einige Anbieter jetzt Server mit 64 TiB (oder mehr) Arbeitsspeicher anbieten, ermöglichen x86_64 und arm64 jetzt die Adressierung von Adressräumen mit mehr als 2 Byte (verfügbar mit der standardmäßigen 48-Bit-Adressunterstützung).

x86_64 adressierte diese Anwendungsfälle, indem es die Unterstützung für fünfstufige Seitentabellen sowohl in der Hardware als auch in der Software ermöglichte. Dies ermöglicht die Adressierung von Adressräumen gleich 2 Bytes (siehe x86:5-Level-Paging-Aktivierung für v4.12 für Details). Es erhöht die Grenzen auf 128 PiB des virtuellen Adressraums und 4 PiB des physischen Adressraums.

arm64 erreichte dasselbe durch die Einführung von zwei neuen Architekturerweiterungen – ARMv8.2 LVA (Large Virtual Addressing) und ARMv8.2 LPA (Large Physical Addressing). Diese erlauben 4 PiB virtuellen Adressraum und 4 PiB physikalischen Adressraum (d. h. jeweils 2 Bit).

Weitere Linux-Ressourcen

  • Spickzettel für Linux-Befehle
  • Spickzettel für fortgeschrittene Linux-Befehle
  • Kostenloser Online-Kurs:RHEL Technical Overview
  • Spickzettel für Linux-Netzwerke
  • SELinux-Spickzettel
  • Spickzettel für allgemeine Linux-Befehle
  • Was sind Linux-Container?
  • Unsere neuesten Linux-Artikel

Mit ARMv8.2-Architekturerweiterungen, die in neuen arm64-CPUs verfügbar sind, werden die beiden neuen Hardwareerweiterungen jetzt in Open-Source-Software unterstützt.

Ab Linux-Kernel-Version 5.4 wurde die Unterstützung für 52-Bit (große) virtuelle Adressen (VA) und physikalische Adressen (PA) für die arm64-Architektur eingeführt. Obwohl die Kernel-Dokumentation diese Funktionen beschreibt und wie sie sich auf die neuen Kernel auswirken, die auf älteren CPUs (die keine 52-Bit-VA-Erweiterung in der Hardware unterstützen) und neueren CPUs (die 52-Bit-VA-Erweiterungen in der Hardware unterstützen) ausgeführt werden, kann dies der Fall sein für durchschnittliche Benutzer komplex, sie zu verstehen und wie sie sich für den Empfang von VAs aus einem 52-Bit-Raum "anmelden" können.

Daher werde ich diese relativ neuen Konzepte in diesem Artikel vorstellen:

  1. Wie das Kernel-Speicherlayout für Arm64 "umgedreht" wurde, nachdem die Unterstützung für diese Funktionen hinzugefügt wurde
  2. Die Auswirkungen auf Userspace-Anwendungen, insbesondere diejenigen, die Debugging-Unterstützung bieten (z. B. kexec-tools, makedumpfile und crash-utility)
  3. Wie sich Userspace-Anwendungen für den Empfang von VAs aus einem 52-Bit-Space „anmelden“ können, indem sie einen mmap-Hinweisparameter angeben, der größer als 48 Bit ist

LVA- und LPA-Erweiterungen der ARMv8.2-Architektur

Die ARMv8.2-Architektur bietet zwei wichtige Erweiterungen:Large Virtual Addressing (LVA) und Large Physical Addressing (LPA).

ARMv8.2-LVA unterstützt einen größeren VA-Speicherplatz für jedes Basisregister der Übersetzungstabelle von bis zu 52 Bit, wenn das 64-KB-Übersetzungsgranule verwendet wird.

ARMv8.2-LPA erlaubt:

  • Eine größere physische Zwischenadresse (IPA) und PA-Speicherplatz von bis zu 52 Bit bei Verwendung des 64-KB-Übersetzungsgranulats
  • Eine Blockgröße der Ebene 1, bei der der Block einen 4-TB-Adressbereich für das 64-KB-Übersetzungsgranulat abdeckt, wenn die Implementierung 52-Bit-PA unterstützt

Beachten Sie, dass diese Funktionen nur im AArch64-Zustand unterstützt werden.

Derzeit unterstützen die folgenden Arm64-Cortex-A-Prozessoren ARMv8.2-Erweiterungen:

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

Weitere Einzelheiten finden Sie im Armv8 Architecture Reference Manual.

Kernel-Speicherlayout auf Arm64

Mit der ARMv8.2-Erweiterung, die Unterstützung für LVA-Speicherplatz hinzufügt (der nur verfügbar ist, wenn er mit einer Seitengröße von 64 KB ausgeführt wird), wird die Anzahl der Deskriptoren in der ersten Übersetzungsebene erweitert.

Benutzeradressen haben die Bits 63:48 auf 0 gesetzt, während die Kerneladressen die gleichen Bits auf 1 gesetzt haben. Die TTBRx-Auswahl wird durch Bit 63 der virtuellen Adresse gegeben. Das swapper_pg_dir enthält nur (globale) Kernel-Mappings, während der Benutzer pgd enthält nur (nicht globale) Benutzerzuordnungen. Das swapper_pg_dir Adresse wird auf TTBR1 geschrieben und niemals auf TTBR0.

AArch64-Linux-Speicherlayout mit 64-KB-Seiten plus drei Ebenen (52-Bit mit Hardwareunterstützung):

  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]

Übersetzungstabellensuche mit 4-KB-Seiten:

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

Übersetzungstabellensuche mit 64-KB-Seiten:

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

52-Bit-VA-Unterstützung im Kernel

Da die neueren Kernel mit LVA-Unterstützung gut auf älteren CPUs (die keine LVA-Erweiterung in der Hardware unterstützen) und den neueren CPUs (die LVA-Erweiterung in der Hardware unterstützen) laufen sollten, besteht der gewählte Designansatz darin, eine einzelne Binärdatei zu haben, die unterstützt 52 Bit (und muss beim frühen Booten auf 48 Bit zurückgreifen können, wenn die Hardwarefunktion nicht vorhanden ist). Das heißt, die VMEMMAP muss groß genug für 52-Bit-VAs sein und muss auch groß genug sein, um einen festen PAGE_OFFSET aufzunehmen .

Dieser Entwurfsansatz erfordert, dass der Kernel die folgenden Variablen für den neuen virtuellen Adressraum unterstützt:

VA_BITS         constant        the *maximum* VA space size

vabits_actual   variable        the *actual* VA space size

Während also VA_BITS bezeichnet die maximale Größe des VA-Speicherplatzes, der tatsächlich unterstützte VA-Speicherplatz (abhängig von der beim Booten vorgenommenen Umstellung) wird durch vabits_actual angezeigt .

Kippen des Kernel-Speicherlayouts

Der Entwurfsansatz, eine einzelne Kernel-Binärdatei beizubehalten, erfordert, dass sich die Kernel-.text in den höheren Adressen befindet, sodass sie gegenüber 48/52-Bit-VAs invariant sind. Da der Schatten des Kernel Address Sanitizer (KASAN) einen Bruchteil des gesamten Kernel-VA-Speicherplatzes ausmacht, muss sich das Ende des KASAN-Schattens auch in der oberen Hälfte des Kernel-VA-Speicherplatzes für 48- und 52-Bit befinden. (Beim Umschalten von 48 Bit auf 52 Bit ist das Ende des KASAN-Schattens unveränderlich und abhängig von ~0UL , während die Startadresse zu den niedrigeren Adressen hin "wächst").

Um phys_to_virt() zu optimieren und virt_to_phys() , der PAGE_OFFSET konstant auf 0xFFF0000000000000 gehalten (entspricht 52 Bit), dies vermeidet die Notwendigkeit eines zusätzlichen Variablenlesens. Die physvirt und vmemmap Offsets werden beim frühen Booten berechnet, um diese Logik zu aktivieren.

Betrachten Sie die folgende Konvertierung des physischen vs. virtuellen RAM-Adressraums:

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

Auswirkung auf Userspace-Anwendungen, die zum Debuggen des Kernels verwendet werden

Mehrere Userspace-Anwendungen werden verwendet, um laufende/aktive Kernel zu debuggen oder den vmcore-Dump von einem abstürzenden System zu analysieren (z. B. um die Hauptursache des Kernel-Absturzes zu ermitteln):kexec-tools, makedumpfile und crash-utility.

Wenn diese zum Debuggen des Arm64-Kernels verwendet werden, hat dies auch Auswirkungen auf sie, da die Speicherzuordnung des Arm64-Kernels "umgedreht" wird. Diese Anwendungen müssen auch einen Translation Table Walk durchführen, um eine physische Adresse zu bestimmen, die einer virtuellen Adresse entspricht (ähnlich wie es im Kernel gemacht wird).

Dementsprechend müssen Userspace-Anwendungen modifiziert werden, da sie nach der Einführung des "Flip" in der Kernel-Memory-Map stromaufwärts beschädigt werden.

Ich habe Korrekturen in den drei betroffenen Userspace-Anwendungen vorgeschlagen; während einige Upstream akzeptiert wurden, stehen andere noch aus:

  • Vorgeschlagene Makedumpfile-Upstream-Korrektur
  • Vorgeschlagene Upstream-Korrektur für kexec-tools
  • Fix im Crash-Dienstprogramm akzeptiert

Wenn diese Änderungen nicht in Userspace-Anwendungen vorgenommen werden, bleiben sie zum Debuggen von laufenden/Live-Kernels oder zum Analysieren des vmcore-Dumps von einem abstürzenden System defekt.

52-Bit-Userspace-VAs

Um die Kompatibilität mit Userspace-Anwendungen aufrechtzuerhalten, die sich auf die maximale Größe des VA-Speicherplatzes von ARMv8.0 von 48 Bit verlassen, gibt der Kernel standardmäßig virtuelle Adressen aus einem 48-Bit-Bereich an den Userspace zurück.

Userspace-Anwendungen können sich für den Empfang von VAs aus einem 52-Bit-Raum "anmelden", indem sie einen mmap-Hinweisparameter angeben, der größer als 48 Bit ist.

Zum Beispiel:

.mmap_high_addr.c
----

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

Es ist auch möglich, einen Debug-Kernel zu bauen, der Adressen aus einem 52-Bit-Bereich zurückgibt, indem die folgenden Kernel-Konfigurationsoptionen aktiviert werden:

   CONFIG_EXPERT=y && CONFIG_ARM64_FORCE_52BIT=y

Beachten Sie, dass diese Option nur zum Debuggen von Anwendungen gedacht ist und nicht sollte in der Produktion verwendet werden.

Schlussfolgerungen

Zusammenfassend:

  1. Beginnend mit der Linux-Kernel-Version 5.14 werden die neuen Armv8.2-Hardwareerweiterungen LVA und LPA jetzt gut im Linux-Kernel unterstützt.
  2. Userspace-Anwendungen wie kexec-tools und makedumpfile, die zum Debuggen des Kernels verwendet werden, sind derzeit defekt und warten auf die Annahme von Upstream-Korrekturen.
  3. Ältere Userspace-Anwendungen, die auf dem Arm64-Kernel basieren und ihm eine 48-Bit-VA bereitstellen, funktionieren unverändert weiter, während neuere Userspace-Anwendungen sich für den Empfang von VAs aus einem 52-Bit-Bereich "anmelden" können, indem sie einen mmap-Hinweisparameter angeben das ist größer als 48 Bit.

Dieser Artikel stützt sich auf das Speicherlayout unter AArch64 Linux und die Linux-Kernel-Dokumentation v5.9.12. Beide sind unter GPLv2.0 lizenziert.


Linux
  1. Der Linux-Kernel:Top 5 Innovationen

  2. Der Lebenszyklus des Linux-Kernel-Testens

  3. Der Status der Hidpi-Unterstützung in Xfce?

  4. Linux – Was bedeutet das virtuelle Kernel-Speicherlayout in Dmesg?

  5. Verständnis des /proc-Dateisystems

Ansible vs. Kubernetes:Die Unterschiede verstehen

So überprüfen Sie die Kernel-Version in Linux

So finden Sie die IP-Adresse einer virtuellen KVM-Maschine

Verstehen des Zeitbefehls in Linux

Verständnis der effektiven Kernel-Version von Ksplice

Woher weiß die CPU, welche physikalische Adresse welcher virtuellen Adresse zugeordnet ist?