GNU/Linux >> Linux Esercitazione >  >> Linux

Comprensione del supporto degli indirizzi virtuali a 52 bit nel kernel Arm64

Dopo che l'hardware a 64 bit è diventato disponibile, è diventata ovvia la necessità di gestire spazi di indirizzi più grandi (maggiori di 2 byte). Con alcuni fornitori che ora offrono server con 64 TiB (o più) di memoria, x86_64 e arm64 ora consentono di indirizzare spazi di indirizzi maggiori di 2 byte (disponibile con il supporto di indirizzi a 48 bit predefinito).

x86_64 ha affrontato questi casi d'uso abilitando il supporto per tabelle di pagine a cinque livelli sia nell'hardware che nel software. Ciò consente di indirizzare spazi di indirizzi pari a 2 byte (vedere x86:abilitazione del paging a 5 livelli per v4.12 per i dettagli). Supera i limiti a 128PiB di spazio di indirizzi virtuali e 4PiB di spazio di indirizzi fisici.

arm64 ha ottenuto lo stesso risultato introducendo due nuove estensioni dell'architettura:ARMv8.2 LVA (Large Virtual Addressing) e ARMv8.2 LPA (Large Physical Addressing). Questi consentono 4 PiB di spazio di indirizzi virtuali e 4 PiB di spazio di indirizzi fisici (cioè 2 bit ciascuno, rispettivamente).

Più risorse Linux

  • Comandi Linux cheat sheet
  • Cheat sheet sui comandi avanzati di Linux
  • Corso online gratuito:Panoramica tecnica RHEL
  • Cheat sheet della rete Linux
  • Cheat sheet di SELinux
  • Cheat sheet dei comandi comuni di Linux
  • Cosa sono i container Linux?
  • I nostri ultimi articoli su Linux

Con le estensioni dell'architettura ARMv8.2 disponibili nelle nuove CPU arm64, le due nuove estensioni hardware sono ora supportate nel software open source.

A partire dalla versione del kernel Linux 5.4, è stato introdotto il supporto per indirizzo virtuale (VA) e indirizzo fisico (PA) a 52 bit per l'architettura arm64. Sebbene la documentazione del kernel descriva queste funzionalità e il modo in cui influiscono sui nuovi kernel in esecuzione su CPU meno recenti (che non supportano l'estensione VA a 52 bit nell'hardware) e CPU più recenti (che supportano estensioni VA a 52 bit nell'hardware), può essere complesso per gli utenti medi per capirli e come possono "attivare" la ricezione di VA da uno spazio a 52 bit.

Pertanto, introdurrò questi concetti relativamente nuovi in ​​questo articolo:

  1. Come è stato "capovolto" il layout della memoria del kernel per Arm64 dopo l'aggiunta del supporto per queste funzionalità
  2. L'impatto sulle applicazioni dello spazio utente, in particolare quelle che forniscono supporto per il debug (ad es. kexec-tools, makedumpfile e crash-utility)
  3. In che modo le applicazioni dello spazio utente possono "accettare" la ricezione di VA da uno spazio a 52 bit specificando un parametro di suggerimento mmap più grande di 48 bit

Estensioni LVA e LPA dell'architettura ARMv8.2

L'architettura ARMv8.2 fornisce due importanti estensioni:Large Virtual Addressing (LVA) e Large Physical Addressing (LPA).

ARMv8.2-LVA supporta uno spazio VA più ampio per ogni registro di base della tabella di traduzione fino a 52 bit quando si utilizza il granulo di traduzione da 64 KB.

ARMv8.2-LPA consente:

  • Un indirizzo fisico intermedio (IPA) e uno spazio PA più grandi fino a 52 bit quando si utilizza il granulo di traduzione da 64 KB
  • Una dimensione del blocco di livello 1 in cui il blocco copre un intervallo di indirizzi di 4 TB per il granello di traduzione da 64 KB se l'implementazione supporta 52 bit di PA

Tieni presente che queste funzionalità sono supportate solo nello stato AArch64.

Attualmente, i seguenti processori Arm64 Cortex-A supportano le estensioni ARMv8.2:

  • Corteccia-A55
  • Corteccia-A75
  • Corteccia-A76

Per maggiori dettagli, vedere il Manuale di riferimento dell'architettura Armv8.

Layout della memoria del kernel su Arm64

Con l'estensione ARMv8.2 che aggiunge il supporto per lo spazio LVA (disponibile solo quando si esegue con una dimensione della pagina di 64 KB), il numero di descrittori viene ampliato nel primo livello di traduzione.

Gli indirizzi utente hanno i bit 63:48 impostati a 0, mentre gli indirizzi del kernel hanno gli stessi bit impostati a 1. La selezione TTBRx è data dal bit 63 dell'indirizzo virtuale. La swapper_pg_dir contiene solo mappature del kernel (globali), mentre l'utente pgd contiene solo mappature utente (non globali). La swapper_pg_dir l'indirizzo viene scritto in TTBR1 e mai in TTBR0.

Layout di memoria Linux AArch64 con pagine da 64 KB più tre livelli (52 bit con supporto 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]

Ricerca nella tabella di traduzione con pagine da 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

Ricerca nella tabella di traduzione con pagine da 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

Supporto VA a 52 bit nel kernel

Poiché i kernel più recenti con supporto LVA dovrebbero funzionare bene su CPU più vecchie (che non supportano l'estensione LVA nell'hardware) e sulle CPU più recenti (che supportano l'estensione LVA nell'hardware), l'approccio progettuale scelto consiste nell'avere un singolo binario che supporti 52 bit (e deve essere in grado di tornare a 48 bit all'avvio anticipato se la funzionalità hardware non è presente). Cioè, il VMEMMAP deve essere sufficientemente grande per VA a 52 bit e deve anche essere sufficientemente grande da contenere un PAGE_OFFSET fisso .

Questo approccio di progettazione richiede che il kernel supporti le seguenti variabili per il nuovo spazio di indirizzi virtuali:

VA_BITS         constant        the *maximum* VA space size

vabits_actual   variable        the *actual* VA space size

Quindi, mentre VA_BITS indica la dimensione massima dello spazio VA, lo spazio VA effettivo supportato (a seconda del passaggio effettuato all'avvio) è indicato da vabits_actual .

Spostamento del layout della memoria del kernel

L'approccio progettuale per mantenere un singolo binario del kernel richiede che il kernel .text si trovi negli indirizzi più alti, in modo tale che siano invarianti rispetto ai VA a 48/52 bit. Poiché l'ombra KASAN (Kernel Address Sanitizer) è una frazione dell'intero spazio VA del kernel, la fine dell'ombra KASAN deve trovarsi anche nella metà superiore dello spazio VA del kernel sia per 48 che per 52 bit. (Passando da 48 bit a 52 bit, la fine dell'ombra KASAN è invariante e dipende da ~0UL , mentre l'indirizzo iniziale "crescerà" verso gli indirizzi inferiori).

Per ottimizzare phys_to_virt() e virt_to_phys() , il PAGE_OFFSET viene mantenuto costante a 0xFFF0000000000000 (corrispondente a 52 bit), ciò ovvia alla necessità di una lettura di variabile aggiuntiva. Il physvirt e vmemmap gli offset vengono calcolati all'avvio anticipato per abilitare questa logica.

Considera la seguente conversione dello spazio degli indirizzi della RAM fisica e virtuale:

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

Impatto sulle applicazioni userspace utilizzate per eseguire il debug del kernel

Diverse applicazioni dello spazio utente vengono utilizzate per eseguire il debug di kernel in esecuzione/live o analizzare il dump di vmcore da un sistema in crash (ad esempio, per determinare la causa principale del crash del kernel):kexec-tools, makedumpfile e crash-utility.

Quando questi vengono utilizzati per il debug del kernel Arm64, c'è anche un impatto su di essi a causa della mappa di memoria del kernel Arm64 che viene "capovolta". Queste applicazioni devono anche eseguire una passeggiata della tabella di traduzione per determinare un indirizzo fisico corrispondente a un indirizzo virtuale (simile a come viene fatto nel kernel).

Di conseguenza, le applicazioni dello spazio utente devono essere modificate poiché vengono interrotte a monte dopo l'introduzione del "flip" nella mappa di memoria del kernel.

Ho proposto correzioni nelle tre applicazioni dello spazio utente interessate; mentre alcuni sono stati accettati a monte, altri sono ancora in attesa:

  • Proposta correzione upstream di makedumpfile
  • Proposta soluzione a monte di kexec-tools
  • Correzione accettata in crash-utility

A meno che queste modifiche non vengano apportate nelle applicazioni dello spazio utente, rimarranno interrotte per il debug di kernel in esecuzione/live o per l'analisi del dump di vmcore da un sistema in crash.

VA spazio utente a 52 bit

Per mantenere la compatibilità con le applicazioni dello spazio utente che si basano sulla dimensione massima dello spazio VA ARMv8.0 di 48 bit, il kernel, per impostazione predefinita, restituirà gli indirizzi virtuali allo spazio utente da un intervallo di 48 bit.

Le applicazioni Userspace possono "accettare" la ricezione di VA da uno spazio a 52 bit specificando un parametro hint mmap maggiore di 48 bit.

Ad esempio:

.mmap_high_addr.c
----

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

È anche possibile creare un kernel di debug che restituisca indirizzi da uno spazio a 52 bit abilitando le seguenti opzioni di configurazione del kernel:

   CONFIG_EXPERT=y && CONFIG_ARM64_FORCE_52BIT=y

Tieni presente che questa opzione è intesa solo per il debug di applicazioni e non essere utilizzato nella produzione.

Conclusioni

Per riassumere:

  1. A partire dalla versione del kernel Linux 5.14, le nuove estensioni hardware Armv8.2 LVA e LPA sono ora ben supportate nel kernel Linux.
  2. Le applicazioni dello spazio utente come kexec-tools e makedumpfile usate per il debug del kernel sono rotte al momento e in attesa di accettazione delle correzioni a monte.
  3. Le applicazioni legacy dello spazio utente che si basano sul kernel Arm64 fornendo un VA a 48 bit continueranno a funzionare così com'è, mentre le applicazioni più recenti dello spazio utente possono "accettare" la ricezione di VA da uno spazio a 52 bit specificando un parametro hint mmap che è maggiore di 48 bit.

Questo articolo si basa su Memory Layout su AArch64 Linux e documentazione del kernel Linux v5.9.12. Entrambi sono concessi in licenza sotto GPLv2.0.


Linux
  1. Il kernel Linux:le 5 migliori innovazioni

  2. Il ciclo di vita dei test del kernel Linux

  3. Linux – Kernel:supporto per gli spazi dei nomi?

  4. Trova il computer su una rete LAN?

  5. Lo stato del supporto Hidpi in Xfce?

Ansible vs Kubernetes:capire le differenze

Come controllare la versione del kernel in Linux

Come trovare l'indirizzo IP di una macchina virtuale KVM

Linux:cosa implica il layout della memoria del kernel virtuale in Dmesg?

Comprendere il comando dell'ora in Linux

A che serve avere una parte del kernel nello spazio di memoria virtuale dei processi Linux?