現在、私は「Linuxカーネルについて」という本を読んでいます。その中には次のような声明があります。
物理アドレス拡張がない32ビットアーキテクチャでは、2つのページングレベルで十分です。 Linuxでは、デフォルトではDirectory-on-PageフィールドとDirectory-in-Pageフィールドにゼロビットが含まれているため削除されます。ただし、ポインタシーケンスでは、ページの親ディレクトリとページの中間ディレクトリの位置が維持されるため、同じコードを32ビットアーキテクチャと64ビットアーキテクチャで動作できます。カーネルは、ページの親ディレクトリとページの中間ディレクトリのエントリ数を1に設定し、これら2つのエントリをページのグローバルディレクトリの正しいエントリにマッピングして、ページの親ディレクトリとページの中間ディレクトリの場所を保存します。 。
したがって、4段階のページングレベルを持つ64ビットLinuxカーネルのページテーブル階層は次のようになります。
PML4 (Linux: PGD) -> 512 * PDPT (Linux: PUD) -> 512 * PD (Linux: PMD) -> 512 * PT
したがって、テキストでは2つのレベルで十分です(通常の32ビットページングと同様)。これがPUDとPMDが「削除」される理由ですが、これら2つのテーブルのうちの1つの長さが1で、シーケンス内の正しい順序が格納されます。 。
私の理解によると、これはPML4(PGD)がPD(PMD)に対応し、PTへの直接ポインタで構成されることを意味します。したがって、PUDとPMDは「スキップ」します。しかし、これは正しくないようです。モードをカーネルモードに切り替えた後にカーネルページにアクセスするには、64ビットページテーブルを使用してページングを実行する必要があるためです。さらに、このマッピングスキームは、4GBの境界(カーネルページなど)を超えるメモリマッピングを許可しません。
別の説明は、32ビットアドレスが64ビットにゼロ拡張され、階層の最初の2つのテーブルに最初のエントリが使用されることです。その後、残りのビットを使用して、残りの2つのテーブルのエントリとページフレーム内のオフセットを選択できます。ただし、各テーブルエントリのビット数が32ビットモードと64ビットモードで異なるため、これも正確ではないようです。したがって、これが問題を引き起こす可能性があります。
だから私が考慮していない部分があったようです。誰かが状況を明確にできることを願っています。
ベストアンサー1
まず、この64ビットシステムでは32ビット実行可能ファイルを実行できません。したがって、32ビットアドレスを64ビットアドレスなどに変換する必要はありません。
第二に、32ビット(PAEなし)は4 GBの境界を超えるメモリマッピングをまったく許可しません。
この質問についてたくさん悩み、何度も読んで答えを見つけました。 StackOverflowで同様の質問をしたことがあります。Linuxカーネルメモリ管理ページングレベル
しかし、私はそれを理解する方法を説明しようとしています。私が説明したいのは、32ビットシステムで4段階のページングが機能する方法です。
最初の文は本当に重要です。
[...]ページディレクトリとページディレクトリフィールドにゼロビットが含まれていると言ってそれを削除します。
これはカーネルを意味しません。セットこれらのフィールドは0ですが、これらのフィールドは0とされていますが、どこかにそれを表現しません。したがって、2レベルのページングに通常の32ビットアドレス分離を使用できます。
これは、PML4仮想アドレス(Linux:PGD)の最上位10ビットを使用することを意味します。
PML4(Linux:PGD)は、エントリが1つしかないPDPT(Linux:PUD)を指します。カーネルではインデックス/オフセットがゼロであるため、この項目のみが使用されます。
PDPT(Linux:PUD)の唯一の項目はPD(Linux:PMD)を指し、この項目にも1つの項目しかありません。再度、カーネルはインデックス/オフセットがゼロであることを示しているため、そのエントリのみが使用されます。
最後に、PD(Linux:PMD)の一意のエントリはPTを指し、仮想アドレスの中間10ビットは目的のページを見つけるためのインデックスとして使用されます。
簡単に言うと:
[1024 *] PML4 (Linux: PGD) -> 1 * PDPT (Linux: PUD) -> 1 * PD (Linux: PMD) -> 1024 * PT