Advertisements

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 (größer als 232 Bytes) wurde offensichtlich. Da einige Anbieter jetzt Server mit 64 TiB (oder mehr) Speicher anbieten, ermöglichen x86_64 und arm64 jetzt die Adressierung von Adressräumen größer als 248 Bytes (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. Damit können Adressräume gleich 2 adressiert werden57 Bytes (Einzelheiten finden Sie unter x86: 5-Level-Paging-Aktivierung für v4.12). 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 ermöglichen 4 PiB virtuellen Adressraum und 4 PiB physischen Adressraum (d. h. 252 Bits jeweils).

Weitere Linux-Ressourcen

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

Beginnend mit der Linux-Kernel-Version 5.4 wurde die Unterstützung für 52-Bit (Large) Virtual Address (VA) und Physical Address (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-Raum “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-Übersetzungsgranulat verwendet wird.

ARMv8.2-LPA ermöglicht:

  • Eine größere physische Zwischenadresse (IPA) und PA-Speicherplatz von bis zu 52 Bits 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
  • Cortex-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 auf 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. Der swapper_pg_dir enthält nur (globale) Kernel-Mappings, während die user pgd enthält nur (nicht globale) Benutzerzuordnungen. Der swapper_pg_dir Adresse wird in TTBR1 geschrieben und niemals in TTBR0 geschrieben.

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

arm64-multi-level-translation.png

opensource.com

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 bemessen sein und muss auch groß genug bemessen sein, um eine feste Größe aufzunehmen PAGE_OFFSET.

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

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

Spiegeln 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”).

Optimieren phys_to_virt() und virt_to_phys(), das PAGE_OFFSET konstant gehalten wird 0xFFF0000000000000 (entspricht 52 Bit), dies vermeidet die Notwendigkeit eines zusätzlichen Variablenlesens. Der 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

Auswirkungen 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 Grundursache 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 stromaufwärts gebrochen werden, nachdem der “Flip” in der Kernel-Speicherabbildung eingeführt wurde.

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-Utility akzeptiert

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

52-Bit-Userspace-VAs

Um die Kompatibilität mit Userspace-Anwendungen aufrechtzuerhalten, die auf der maximalen Größe des VA-Speicherplatzes von ARMv8.0 von 48 Bit basieren, 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.

Beispielsweise:

.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 Sie die folgenden Kernel-Konfigurationsoptionen aktivieren:

   CONFIG_EXPERT=y && CONFIG_ARM64_FORCE_52BIT=y

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

Schlussfolgerungen

Zusammenfassen:

  1. Ab 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 defekt im Augenblick und Warten auf die Annahme von Upstream-Korrekturen.
  3. Legacy-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 größeren mmap-Hinweisparameter angeben 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.

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

Leave a Reply

Your email address will not be published. Required fields are marked *

Scroll to top