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:
- Wie das Kernel-Speicherlayout für Arm64 "umgedreht" wurde, nachdem die Unterstützung für diese Funktionen hinzugefügt wurde
- Die Auswirkungen auf Userspace-Anwendungen, insbesondere diejenigen, die Debugging-Unterstützung bieten (z. B. kexec-tools, makedumpfile und crash-utility)
- 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:
- Beginnend mit der Linux-Kernel-Version 5.14 werden die neuen Armv8.2-Hardwareerweiterungen LVA und LPA jetzt gut im Linux-Kernel unterstützt.
- 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.
- Ä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.