回答:
32ビットアーキテクチャでは、RAMをアドレス指定するためのアドレス空間の範囲は次のとおりです。
0x00000000 - 0xffffffff
または4'294'967'295
(4 GB)。
Linuxカーネルは、それを3/1(2/2または1/3 1でも可)に分割し、それぞれユーザースペース(高メモリ)とカーネルスペース(低メモリ)に分割します。
ユーザー空間の範囲:
0x00000000 - 0xbfffffff
新しく生成されたすべてのユーザープロセスは、この領域内のアドレス(範囲)を取得します。ユーザープロセスは一般的に信頼されていないため、カーネルスペースへのアクセスは禁止されています。さらに、それらは一般的なルールとして、緊急ではないと見なされます。カーネルは、これらのプロセスへのメモリの割り当てを延期しようとします。
カーネル空間の範囲:
0xc0000000 - 0xffffffff
カーネルプロセスは、ここでそのアドレス(範囲)を取得します。カーネルはこの1 GBのアドレスに直接アクセスできます(1 GB全体ではなく、高メモリアクセス用に128 MBが予約されています)。
カーネル空間で生成されたプロセスは信頼され、緊急であり、エラーがないと想定され、メモリ要求は即座に処理されます。
すべてのカーネルプロセスは、必要に応じてユーザー空間の範囲にもアクセスできます。これを実現するために、カーネルはユーザー空間(高メモリ)からそのカーネル空間(低メモリ)にアドレスをマッピングします。上記の128 MBは特にこのために予約されています。
1スプリットが3 / 1、2 / 2、または1/3のいずれであるかは、CONFIG_VMSPLIT_...
オプションによって制御されます。おそらく、/boot/config*
どのオプションがカーネル用に選択されているかを確認するために下で確認できます。
最初に参照するのは、Linuxデバイスドライバー(オンラインと書籍の両方で入手可能)、特にトピックに関するセクションがある第15章です。
理想的な世界では、すべてのシステムコンポーネントは、アクセスする必要があるすべてのメモリをマップできます。そして、これはLinuxおよびほとんどのオペレーティングシステム上のプロセスに当てはまります。32ビットプロセスは2 ^ 32バイト未満の仮想メモリにしかアクセスできません(実際、典型的なLinux 32ビットアーキテクチャでは約3GB)。カーネルにとっては難しくなります。カーネルは、システムコールが実行しているプロセスの全メモリ、物理メモリ全体、および他のメモリマップハードウェアデバイスをマップできる必要があります。
そのため、32ビットカーネルが4 GBを超えるメモリをマップする必要がある場合、高メモリサポートでコンパイルする必要があります。高メモリとは、カーネルのアドレス空間に永続的にマップされないメモリです。(低メモリは逆です。常にマップされているため、ポインタを間接参照するだけでカーネルでアクセスできます。)
カーネルコードからハイメモリにアクセスする場合は、kmap
最初に呼び出して、ページデータ構造(struct page
)からポインターを取得する必要があります。呼び出しkmap
は、ページのメモリが高いか低いかに関係なく機能します。kmap_atomic
制約が追加されたものもありますが、きめ細かいロックを使用するため、マルチプロセッサマシンではより効率的です。取得されるポインタkmap
はリソースです。アドレス空間を使い果たします。終了したら、kunmap
(またはkunmap_atomic
)を呼び出してそのリソースを解放する必要があります。ポインタは無効になり、kmap
再度呼び出すまでページのコンテンツにアクセスできなくなります。
これはLinuxカーネルに関連しています。Unixカーネルがこれをどのように処理するかはわかりません。
ハイメモリは、ユーザー空間プログラムがアドレスできるメモリのセグメントです。低メモリに触れることはできません。
低メモリは、Linuxカーネルが直接アドレス指定できるメモリのセグメントです。カーネルがハイメモリにアクセスする必要がある場合は、まずカーネルを独自のアドレススペースにマップする必要があります。
セグメントの場所を制御できるパッチが最近導入されました。トレードオフは、アドレス可能なメモリをユーザー空間から取り去ることができるため、使用する前にマップする必要のないより多くのメモリをカーネルが持つことができることです。
追加のリソース:
HIGHMEMはカーネルのメモリ空間の範囲ですが、アクセスするメモリではありませんが、アクセスしたいものを置く場所です。
典型的な32ビットLinux仮想メモリマップは次のとおりです。
0x00000000-0xbfffffff:ユーザープロセス(3GB)
0xc0000000-0xffffffff:カーネルスペース(1GB)
(ここでは、CPU固有のベクトルなどは無視されます)。
Linuxは、1GBのカーネルスペースをLOWMEMとHIGHMEMの2つの部分に分割します。分割はインストールごとに異なります。
たとえば、LOWおよびHIGHメモリに512MB-512MBを選択すると、カーネルのブート時に512MB LOWMEM(0xc0000000-0xdfffffff)が静的にマッピングされます。通常、物理メモリの最初の非常に多くのバイトがこのために使用されるため、この範囲の仮想アドレスと物理アドレスは、たとえば0xc0000000の一定のオフセットを持ちます。
一方、後者の512MB(HIGHMEM)には静的なマッピングがありません(ただし、ページを半永久的にマッピングしたままにすることはできますが、ドライバーコードで明示的に行う必要があります)。代わりに、ここでページが一時的にマッピングおよびマッピング解除されるため、この範囲の仮想アドレスと物理アドレスには一貫したマッピングがありません。HIGHMEMの一般的な用途には、シングルタイムデータバッファが含まれます。