64ビットLinuxカーネルは、互換モードで32ビットアプリケーションのページテーブルをどのように管理しますか?

64ビットLinuxカーネルは、互換モードで32ビットアプリケーションのページテーブルをどのように管理しますか?

現在、私は「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

おすすめ記事