カーネル(その6)
前々回、プロセススイッチの概念的な仕組みを紹介した。
今回はそれを実現する onix データ構造及び、前回まではサポートしていなかったユーザープロセス処理について話をする。
プログラムソースは
http://sourceforge.jp/projects/onix/
で svn リポジトリを公開している。
まず、プロセスのデータ構造について見てゆく。
各プロセス固有の情報を持ったデータ構造は、struct process [process.h] で定義されている。各プロセスが持たなければならないオブジェクトとして、ページテーブル、スタック領域がある。又、プロセスのパラメータとして、ID, 特権レベル, 各種 CPU セグメントがある。
更に、後述するユーザープロセスをプリエンプティブする時に読み出される各プロセス共通の TSS ディスクリプタを持つ。
加えて、以前に話した実行プロセスのリンクリスト構造を持つ。
プロセスディスクリプタと TSS ディスクリプタで幾つかの CPU レジスタ情報が重複して存在しており、冗長であると思われるかもしれないが、TSS ディスクリプタは各プロセス共通で利用する為に、各プロセス固有の情報を表すプロセスディスクリプタにレジスタ情報が存在している。ならば、TSS を各プロセス固有の情報にしてしまえという考えもあるが、以前に書いたように linux 同様ユーザープロセスのプリエンプティブ以外において TSS ディスクリプタを利用していないので、それに依存した処理を書きたくない。
又、プロセスの特権レベルの情報をカーネルデータ構造に持たせるのも冗長かもしれない。何故なら、CS レジスタの下位 2 bit によって現行プロセスの CPL がわかるからである。これを利用すれば、処理も高速になりそう(*1)である。
しかし、割り込みハンドラなどによって、処理が一時的にカーネルに移った際に現行プロセスの特権レベルを把握する為には、メモリに退避させる必要がある。
(*1) : メモリアクセスを行わない為
次に、プロセス生成処理について見てゆく。
プロセス作成のコアルーチンは create_process_discripter() になる。
ここでは、Kernel DATA スラブディレクトリからプロセスディスクリプタ用のメモリ領域の取得、初期化を行い、実行プロセスリストに追加する。
ただし、ページディレクトリ用のメモリ領域だけは、Page Directory Table スラブディレクトリから取得する。これは、CR3 レジスタに格納される物理アドレスは、0x1000 でアライメントされている必要がある為である。
プロセスの開放時には、プロセスディスクリプタ及び、ページディレクトリテーブルのメモリ領域、そしてまだ未実装だが、プロセスが取得したメモリ領域を管理するリストに載っている領域、更に命令本体のメモリ領域を開放する事で、プロセスを開放できる (未実装)。
次に、プロセススイッチを実現するタイマ割り込みについて話をする。
処理の概要については前々回に話をしたので、ここではユーザープロセスの切り替えについてみてゆく。
プロセスの切り替えがタイマ割り込みによってのみ行われるという設計方針は間違っているので、他のゲートからプロセススイッチが可能となるように処理を修正するつもりだが、基本的な処理はここで話す内容と変わらない。
先述したように、コードセグメントセレクタの下位 2 bitは、現在 CPU を利用しているプロセスの特権レベル(CPL : Current Privilege Level)を表している。割り込み発生時、対象の割り込みハンドラが存在するセグメントの DPL よりも CPL の特権レベルが低い場合、TSS ディスクリプタの ESP と SS を参照し、これを書き換える。この ESP レジスタが指す場所は、ユーザープロセスがカーネル実行パスを処理する際にのみ利用される領域であり、世間ではカーネルスタックと呼ばれたりしている。
後は、同一特権レベルからの割り込み時と同様に処理が行える。ただしユーザープロセスの場合、スタックポインタの値は TSS ディスクリプタのそれを指しているので、この値は意味を持たない。ユーザープロセスからの割り込み発生時には、元のスタックポインタの値とコードセグメントはスタックに存在するので、スタックを掘り起こしてユーザープロセスのスタックポインタの値を取得する。
更に、現在実行中の特権レベルと違う特権レベルに処理を移す場合 iret を実行する直前に、プログラムカウンタ、コードセグメントセレクタ、フラグレジスタに加えて、スタックポインタ、スタックセグメントセレクタをスタックに積む必要がある。又、他の各種セグメントレジスタをユーザーデータセグメントセレクタに修正する。
他のゲートにおいても、上述した内容の処理を行う事で、ユーザー空間とカーネル空間を自由に行き来する事が出来る。
これで、TSS (Time Sharing System) の基礎は完成したといっていい。プロセス関連処理については、高級な処理の多くが未実装であるが、最もプリミティブな部位の実装と動作確認を終えたので、次はファイルシステムを作ろうと思う。
- Category(s)
- 学習経過
- The URL to Trackback this entry is:
- http://dev.ariel-networks.com/Members/ohyama/30ab30fc30cd30eb-305d306e6/tbping