64ビットハードウェアが利用可能になった後、より大きなアドレス空間(2バイトを超える)を処理する必要性が明らかになりました。一部のベンダーは現在、64TiB(またはそれ以上)のメモリを備えたサーバーを提供していますが、x86_64およびarm64では、2バイトを超えるアドレススペースのアドレス指定が可能になりました(デフォルトの48ビットアドレスサポートで利用可能)。
x86_64は、ハードウェアとソフトウェアの両方で5レベルのページテーブルのサポートを有効にすることで、これらのユースケースに対処しました。これにより、2バイトに等しいアドレス空間のアドレス指定が可能になります(詳細については、x86:v4.12で有効になっている5レベルのページングを参照してください)。制限を128PiBの仮想アドレス空間と4PiBの物理アドレス空間に引き上げます。
arm64は、ARMv8.2 LVA(大規模仮想アドレス指定)とARMv8.2 LPA(大規模物理アドレス指定)という2つの新しいアーキテクチャ拡張機能を導入することで同じことを実現しました。これらにより、4PiBの仮想アドレス空間と4 PiBの物理アドレス空間(つまり、それぞれ2ビット)が可能になります。
その他のLinuxリソース
- Linuxコマンドのチートシート
- 高度なLinuxコマンドのチートシート
- 無料のオンラインコース:RHELの技術概要
- Linuxネットワーキングのチートシート
- SELinuxチートシート
- Linuxの一般的なコマンドのチートシート
- Linuxコンテナとは何ですか?
- 最新のLinux記事
新しいarm64CPUで利用可能なARMv8.2アーキテクチャ拡張機能により、2つの新しいハードウェア拡張機能がオープンソースソフトウェアでサポートされるようになりました。
Linuxカーネルバージョン5.4以降、arm64アーキテクチャに52ビット(大)仮想アドレス(VA)と物理アドレス(PA)のサポートが導入されました。カーネルのドキュメントでは、これらの機能と、古いCPU(ハードウェアで52ビットVA拡張をサポートしない)および新しいCPU(ハードウェアで52ビットVA拡張をサポートする)で実行される新しいカーネルにどのように影響するかについて説明していますが、平均的なユーザーがそれらを理解し、52ビットスペースからのVAの受信に「オプトイン」する方法を理解するには複雑です。
したがって、この記事ではこれらの比較的新しい概念を紹介します。
- これらの機能のサポートが追加された後、Arm64のカーネルメモリレイアウトがどのように「反転」したか
- ユーザースペースアプリケーション、特にデバッグサポートを提供するアプリケーション(kexec-tools、makedumpfile、crash-utilityなど)への影響
- ユーザースペースアプリケーションが、48ビットより大きいmmapヒントパラメータを指定することにより、52ビットスペースからのVAの受信に「オプトイン」する方法
ARMv8.2アーキテクチャLVAおよびLPA拡張機能
ARMv8.2アーキテクチャは、ラージ仮想アドレス指定(LVA)とラージ物理アドレス指定(LPA)の2つの重要な拡張機能を提供します。
ARMv8.2-LVAは、64KB変換グラニュールを使用する場合、最大52ビットの変換テーブルベースレジスタごとに、より大きなVAスペースをサポートします。
ARMv8.2-LPAでは次のことが可能です:
- 64KBの変換グラニュルを使用する場合、最大52ビットのより大きな中間物理アドレス(IPA)とPAスペース
- 実装が52ビットのPAをサポートしている場合、ブロックが64KB変換グラニュルの4TBアドレス範囲をカバーするレベル1ブロックサイズ
これらの機能はAArch64状態でのみサポートされていることに注意してください。
現在、次のArm64Cortex-AプロセッサがARMv8.2拡張機能をサポートしています。
- Cortex-A55
- Cortex-A75
- Cortex-A76
詳細については、Armv8アーキテクチャリファレンスマニュアルを参照してください。
Arm64のカーネルメモリレイアウト
ARMv8.2拡張機能がLVAスペース(64KBのページサイズで実行している場合にのみ使用可能)のサポートを追加すると、記述子の数が第1レベルの変換で拡張されます。
ユーザーアドレスのビット63:48は0に設定されていますが、カーネルアドレスの同じビットは1に設定されています。TTBRxの選択は、仮想アドレスのビット63によって行われます。 swapper_pg_dir
ユーザーがpgd
であるのに対し、カーネル(グローバル)マッピングのみが含まれます ユーザー(非グローバル)マッピングのみが含まれます。 swapper_pg_dir
アドレスはTTBR1に書き込まれ、TTBR0には書き込まれません。
64KBページと3つのレベル(ハードウェアサポート付きの52ビット)を備えたAArch64 Linuxメモリレイアウト:
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]
4KBページの変換テーブルルックアップ:
+--------+--------+--------+--------+--------+--------+--------+--------+
|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
64KBページの変換テーブルルックアップ:
+--------+--------+--------+--------+--------+--------+--------+--------+
|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
LVAをサポートする新しいカーネルは古いCPU(ハードウェアでLVA拡張をサポートしない)と新しいCPU(ハードウェアでLVA拡張をサポートする)でうまく動作するはずなので、選択した設計アプローチは、サポートする単一のバイナリを使用することです。 52ビット(ハードウェア機能が存在しない場合は、起動時に48ビットにフォールバックできる必要があります)。つまり、VMEMMAPは、52ビットVAに十分なサイズである必要があり、固定のPAGE_OFFSET
に対応するのに十分なサイズである必要があります。 。
この設計アプローチでは、カーネルが新しい仮想アドレス空間に対して次の変数をサポートする必要があります。
VA_BITS constant the *maximum* VA space size
vabits_actual variable the *actual* VA space size
つまり、VA_BITS
最大VAスペースサイズを示します。サポートされる実際のVAスペース(起動時に行われたスイッチによって異なります)は、vabits_actual
で示されます。 。
単一のカーネルバイナリを保持する設計アプローチでは、カーネル.textが48/52ビットVAに対して不変であるように、より高いアドレスにある必要があります。カーネルアドレスサニタイザー(KASAN)シャドウはカーネルVAスペース全体の一部であるため、KASANシャドウの終わりも48ビットと52ビットの両方でカーネルVAスペースの上位半分にある必要があります。 (48ビットから52ビットに切り替えると、KASANシャドウの終わりは不変であり、~0UL
に依存します。 、開始アドレスは下位アドレスに向かって「成長」します。
phys_to_virt()
を最適化するには およびvirt_to_phys()
、PAGE_OFFSET
0xFFF0000000000000
で一定に保たれます (52ビットに対応)、これにより、余分な変数の読み取りが不要になります。 physvirt
およびvmemmap
このロジックを有効にするために、初期起動時にオフセットが計算されます。
次の物理RAMと仮想RAMのアドレス空間変換を検討してください。
/*
* 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
実行中/ライブカーネルをデバッグしたり、クラッシュしたシステムからのvmcoreダンプを分析したりするために(たとえば、カーネルクラッシュの根本原因を特定するために)、kexec-tools、makedumpfile、crash-utilityなどのいくつかのユーザースペースアプリケーションが使用されます。
これらをArm64カーネルのデバッグに使用すると、Arm64カーネルのメモリマップが「反転」するため、これらにも影響があります。これらのアプリケーションは、仮想アドレスに対応する物理アドレスを決定するために変換テーブルウォークを実行する必要もあります(カーネルで行われる方法と同様です)。
したがって、ユーザースペースアプリケーションは、カーネルメモリマップに「フリップ」が導入された後にアップストリームで中断されるため、変更する必要があります。
影響を受ける3つのユーザースペースアプリケーションの修正を提案しました。上流で受け入れられたものもあれば、まだ保留中のものもあります:
- 提案されたmakedumpfileアップストリーム修正
- 提案されたkexec-toolsアップストリーム修正
- crash-utilityで受け入れられた修正
これらの変更がユーザースペースアプリケーションで行われない限り、実行中/ライブカーネルのデバッグや、クラッシュしているシステムからのvmcoreダンプの分析のために壊れたままになります。
52ビットのユーザースペースVA
ARMv8.0 VAスペースの最大サイズ48ビットに依存するユーザースペースアプリケーションとの互換性を維持するために、カーネルはデフォルトで仮想アドレスを48ビット範囲からユーザースペースに返します。
ユーザースペースアプリケーションは、48ビットより大きいmmapヒントパラメータを指定することにより、52ビットスペースからのVAの受信に「オプトイン」できます。
例:
.mmap_high_addr.c
----
maybe_high_address = mmap(~0UL, size, prot, flags,...);
次のカーネル構成オプションを有効にすることで、52ビットスペースからアドレスを返すデバッグカーネルを構築することもできます。
CONFIG_EXPERT=y && CONFIG_ARM64_FORCE_52BIT=y
このオプションはアプリケーションのデバッグのみを目的としており、使用しないことに注意してください。 本番環境で使用できます。
要約すると:
- Linuxカーネルバージョン5.14以降、新しいArmv8.2ハードウェア拡張機能LVAおよびLPAがLinuxカーネルで十分にサポートされるようになりました。
- カーネルのデバッグに使用されるkexec-toolsやmakedumpfileなどのユーザースペースアプリケーションが壊れています現在 上流の修正が受け入れられるのを待っています。
- 48ビットVAを提供するArm64カーネルに依存するレガシーユーザースペースアプリケーションはそのまま動作し続けますが、新しいユーザースペースアプリケーションは、mmapヒントパラメーターを指定することで52ビットスペースからのVAの受信に「オプトイン」できます。これは48ビットより大きいです。
この記事は、AArch64LinuxおよびLinuxカーネルのドキュメントv5.9.12のメモリレイアウトを利用しています。どちらもGPLv2.0でライセンスされています。