Linuxカーネルメモリ管理リファレンス

Linuxカーネルメモリ管理リファレンス

Linux Device Driversの本から抜粋したものを理解するのに苦労しています(申し訳ありませんが、この投稿はテキストが多すぎます)。

カーネル(x86アーキテクチャでデフォルト設定)は、ユーザースペースとカーネルの間に4 GBの仮想アドレススペースを分割します。両方のコンテキストで同じマッピングセットが使用されます。一般的な分割では、ユーザースペースに3GB、カーネルスペースに1GBを割り当てます。

わかりました、わかりました。

カーネルのコードとデータ構造はそのスペースに収まるべきですが、カーネルアドレス空間を最も消費するのは、物理メモリの仮想マッピングです。

どういう意味ですか?カーネルのコードとデータ構造も「物理アドレス空間にマップされた仮想メモリ」にありませんか?これらのコードとデータ構造はどこに保存されていますか?

それとも、ドライバ、IPC、またはその他の手段を介して操作するカーネルに関連付けられていない任意のデータをマッピングするために、カーネルに仮想アドレス空間が必要ですか?

カーネルは、カーネルアドレス空間にマップされていないメモリでは直接動作できません。つまり、カーネルには直接アクセス可能なメモリを格納するために独自の仮想アドレスが必要です。

これは本当ですか?カーネルがプロセスコンテキスト(システムコール処理)で実行されている場合、プロセスのページテーブルは引き続きロードされますが、なぜカーネルはユーザーモードのプロセスメモリを直接読み取ることができないのですか?

したがって、カーネルが長年処理できる物理メモリの最大量は、カーネルコード自体に必要なスペースを引いたカーネルの仮想アドレス空間部分にマッピングできる量でした。

いいですね。私が引用文#2を正しく理解したならば、この言葉が理解されます。

したがって、x86 ベースの Linux システムでは、最大 1 GB 未満の物理メモリを使用できます。

????完全に非論理的なようです。なぜ4GBのメモリを使用し、必要に応じて他のものをカーネルで利用可能な1GBにマップできないのですか? 〜1GBのカーネルスペースしかないと、システムが4GBで実行できないことを意味するのはなぜですか?一度にマッピングする必要はありません。

答え1

なぜ4GBのメモリが利用できず、必要に応じて他のものをカーネルで利用可能な1GBにマップできないのですか?

これはHIGHMEM、直接マッピングに適していないメモリに対して設定オプションが実行するアクションです。ただし、これはメモリ内の任意の場所にアクセスする必要がある場合に問題になります。簡単に毎回マッピングを設定せずに直接指すことができれば可能です。これには、常にすべての物理メモリにマップされる仮想メモリ領域が必要です。これは、仮想アドレス空間が物理アドレス空間より小さい場合は実行できません。

直接接続もより速く、vm/highmem.txtカーネル文書から説明する:

一時マッピングを作成するためのコストはかなり高くなる可能性があります。アーキテクチャは、コアのページテーブル、データTLB、および/またはMMUレジスタを操作する必要があります。

もちろん、ユーザー空間マップを介して実行中のプロセスのメモリにアクセスでき、他のプロセスのメモリにアクセスすることを避けることもできます。ただし、ページキャッシュなどの大規模なカーネルデータ構造がある場合は、すべてのメモリが利用可能であればよいでしょう。

全体的な内容は少しです。銀行の切り替え、これはDOS時代に16ビットシステムと386/486システムで使用されていました(ヒメムシステム)。私はその時もこのようなメモリにアクセスするのが特に好きではなかったと思います。これは、物理メモリの複数の領域を同時に「開く」必要がある場合、状況がかなり難しくなるためです。 32ビットシステムに進化した後、64ビットシステムに進化してこの問題を解決しました。

答え2

カーネルがプロセスコンテキスト(システムコール処理)で実行されている場合、プロセスのページテーブルは引き続きロードされますが、なぜカーネルはユーザーモードのプロセスメモリを直接読み取ることができないのですか?

この文脈では、「カーネルアドレス空間」という用語は、ユーザーアドレス空間とは逆に解釈されるべきではありません。代わりに、カーネルがアクセスする必要があるメモリをいくつかの仮想アドレスにマップする必要があることを意味します。この本の著者が言いたいのはここにあります。したがって、「カーネルのアドレス空間」は完全なマップである。

答え3

それができます。 「数年間」ではなく、そんなに多くの記憶力を持つ人が誰もいなかったので、そもそもそうする理由はありませんでした。

読み続け、注意深く見てください。

ただし、論理アドレスに直接マッピングできるメモリ量にはまだ制限があります。メモリの最下部(ハードウェアおよびカーネル構成によっては最大1 GBまたは2 GB)にのみ論理アドレスがあり、[2]残り(より高いメモリ)にはありません。特定の大容量メモリページにアクセスする前に、カーネルはカーネルアドレス空間でそのページを使用できるように明示的な仮想マッピングを設定する必要があります。したがって、多くのカーネルデータ構造は低メモリに配置する必要があります。高メモリは、しばしばユーザースペースプロセスページ用に予約されています。


カーネルがプロセスコンテキスト(システムコール処理)で実行されている場合、プロセスのページテーブルは引き続きロードされますが、なぜカーネルはユーザーモードのプロセスメモリを直接読み取ることができないのですか?

もちろん

https://www.quora.com/Linux-Kernel-How-does-copy_to_user-work


kmalloc()通常、カーネルに割り当てられた構造を使用すると、直接マップされた範囲内で約1 GBのメモリが返されることを知っておくと便利です。だから可愛くてアクセスしやすいです。

(コストは、このようなさまざまなタイプの割り当て形式によって複雑さが発生することです。

標準kmalloc()割り当てでRAMの25%以上を使用できるようにするには、やや面倒な作業を行う必要があります。しかし、正式な答えは、30ビット以上の物理RAMを備えた既存の32ビットシステムでこのような厳しいワークロードを実行してはいけません。

この特定の詳細に本当に興味がある場合は、2つの異なる点を見つけました。

1. 1GBの制限するRAMに制限を置きますが、もう少し高くしてください。

https://www.redhat.com/archives/rhl-devel-list/2005-January/msg00092.html

インターネット検索によると、大容量RAM(32 GB以上)のシステムでは、カーネルメモリテーブルが物理メモリサイズに応じて拡張されるため、4G:4Gパッチが必要ですが、32GBシステムは3G:1Gシステムで利用可能な0.5GBテーブルを使用します。することがわかりました。カーネル空間の半分。 64GBシステムはテーブルにすべてのカーネルメモリが必要なため、起動できません。

4G:4Gパッチはもう一つの話です。しかし、メインラインLinuxにはないので無視しても構いません。

CONFIG_HIGHMEM64Gを有効にすることができるので(i386、つまり32ビット)、これらの制限も克服されているようです。おそらくこれに依存しないのが最善です。それとも何をすべきかを考えてみましょう。

2. ページテーブルには直接マッピングは厳密には必要ありません。

多くの一般的なオペレーティングシステムの作成チュートリアルと練習では、「再帰ページテーブル」という興味深い技術を使用しています。

https://www.google.co.uk/search?q=recursive+page+tables

Linuxはこの方法を使用しないため、既存のLinuxが理解しやすくなります。 〜1GBの「低メモリ」の直接マッピングは初期ページテーブルに設定され、変更されません。ページテーブルは「低メモリ」から割り当てられます。

(CONFIG_HIGHMEM64Gが今何をしているのか疑問に思っていますか?やめてください。これはあなたにとって良いことではありません。)

私はLinusが再帰的なトリックを全く考えていないと思います。 IIRCには適切なサイズの直接マップがないという点で他の欠点がありますが、具体的な例は不明です。

私は「伝統的なLinux」と言いました。 KPTIが実際に32ビットにマージされたかどうかは聞いたことがありませんが、それでもKPTIは全体的なアイデアを変えてはいけません。ユーザーページテーブルからカーネルページテーブルに切り替えると、カーネルは直接マッピングにアクセスできます。移行プロセスは素晴らしい黒魔法ですが、すべてのコンテキスト移行で実行されます。ユーザースペースページテーブルには直接マッピングは含まれていませんが、ユーザースペースはページテーブルなどにアクセスできず、アクセスしないでください。したがって、すべてが正常です。

関連情報