/usr/src/linux/include/asm-i386/page.h /usr/src/linux/arch/i386/vmlinux.lds
カーネル空間は、単純な物理メモリのストレートマッピングで実現されています。
プロテクションなどの恩恵を受けることができないデメリットがありますが、
逆にどこからでもカーネル内の全てのデータ構造を参照でき、
またカーネルデータを指すポインタを使いまわすことが可能であるという
メリットもあります。
v2.4からは2Gbyte以上の物理メモリを利用することができるようになりました。
これらのメモリは物理メモリにストレートマッピングできないため、
必要に応じて動的に仮想空間にマッピングしアクセスさます。
動的に物理メモリを仮想空間へマッピングする領域としては、
カーネル空間の最後の128Mbyteが予約されています。
仮想空間の生成は, 仮想空間管理構造体vm_area_structのアロケートと, そのvm_area_structに対応するPGD,PTEの初期化を行うことです。 プロセス空間の生成/拡張はdo_mmap関数、do_brk関数で実現しています。
do_mmap(ファイル構造体、アドレス、サイズ、プロテクション...) { 固定仮想アドレス指定で無い場合、空いている仮想空間を検索する。 仮想空間管理構造体vm_area_structを確保する。 vm_area_structを初期化、仮想空間を予約する。 if (ファイル指定?) { 仮想空間管理構造体vm_area_structにファイル構造体を登録 ファイル構造体のmmapオペレーションを呼び出す。 (ext2fsの場合はgeneric_file_mmap関数) } 可能なら隣り合ったvm同士でマージする(merge_segments関数) } do_brk(アドレス、サイズ) { 仮想空間管理構造体vm_area_structを確保する。 vm_area_structを初期化、仮想空間を予約する。 可能なら隣り合ったvm同士でマージする(merge_segments関数) }生成されたばかりのプロセス空間は、仮想空間だけは存在しますが、 PTEの中身は全て空であり、物理メモリは割り当てられていません。 生成直後の仮想空間(ページ)にアクセスをすると, まだ実際には物理メモリが 割り当てられていないため、CPU例外が発生します。そのときlinuxでは、 do_no_page関数が呼び出されます。
do_no_page(タスク、仮想空間管理構造体vm_area_struct、アドレス...) { if (ファイルマップされていない領域?) { 単純物理ページ確保とマップ(do_anonymous_page関数) return; } 仮想空間管理構造体vm_area_structのnopageオペレーションを呼び出す。 (ext2fsの場合は、 filemap_nopage関数) pteのデータを生成(mk_pte関数) if(書きこみアクセスか) { 書きこみ可とする(pte_mkwrite関数) dirtyのビットも立てておく(pte_mkdirty関数) } else if (共有mmapでないが、複数のプロセスで共有している) { 書きこみ禁止とする(pte_wrprotect関数) (※これに関しては、コピーオンライトの説明を見よ) } 実際のページテーブルに登録(set_pte関数) }メモリが不足してくると参照頻度の低いページはtry_to_swap_out関数で スワップデバイスに追い出されます。空きスワップ域を検索し、そこに 物理メモリの内容を書き込み, 物理メモリを解放します。PTEにはスワップ 先を示すインデックスを書き込んでおきます。 まだ一度も書き込みを行っていないページの場合は, スワップデバイスに 追い出さず, 単に物理メモリの解放と PTEのクリアを行います。
一度スワップアウトされたページへのアクセスが発生すると、CPU例外が発生します。 このときlinuxはdo_swap_page関数を呼び出します。 この関数では、例外を発生した空間に対するスワップ上のブロックの内容を 空き物理ページに読み込み、その物理ページをこの空間を管理するpteに登録します。
do_swap_page(タスク、仮想空間管理構造体vm_area_struct, アドレス、....) { swapキャッシュを検索(lookup_swap_cache関数) if (swapキャッシュ上にない) { swapデバイスからswapキャッシュに読み込む. (swapin_readahead関数、read_swap_cache関数) } swapデバイス上の領域の参照数を1減らす(swap_free関数) if (書き込みアクセスで、かつ共有領域でない) { swapキャッシュから削除(delete_from_swap_cache_nolock関数) 書きこみ可、dirtyビットオン、でページを指すpteを作成する。 (pte_mkwrite関数、pte_mkdirty関数、mk_pte関数) } else { ページを指すpteを作成する(mk_pte関数) } pteを実際のページテーブルに登録(set_pte関数) }
v2.4からはフリーページはzoneと呼ばれる複数の領域に分けて 管理されるようになりました。 すなわち、normal zone, HighMem zone, DMA zoneです。v2.2までと異なり、カーネル空間に ストレートマッピングすることのできない領域の物理メモリまで 管理できるようにするために、二つの領域を明確に別のzoneとして 分離管理しています。 カーネル空間にストレートマッピング されていない領域は HighMemと呼ばれ、アクセス前には仮想空間に マップするという処理が必要となります。 伝統的UNIXでは、通常カーネル空間に全ての物理メモリを ストレートマッピングするという手法はとっていないため、 このような区別はありません。 また、更にDMA可能領域も意識し、別のzoneとして管理しなければならないのは、 古いPCのアーキティクチャに縛られているためです。 また、v2.4からは非連続な物理メモリ領域を管理するための汎用的なコードが 追加されました。ただし、Intel+ PC/ATアーキティクチャのマシンでは 物理メモリ領域は1つのみです。
主な操作関数群