OS作成 - ページング&プロセス編
非TSSタスクスイッチ時のPriviledge Levelの推移を中心に考察(というかマインドストーミング)
1. カーネルをユーザプロセス(init)に移行させるにはどうするか。
- CPL0で稼働しているカーネルをCPL3に移行する必要がある。
- 現在書いているコードのスイッチ部分ではCPLは一切変化しない(CPL0のまま)
- ではどこでCPLを変えるか?
- スケジューラで変えてみるのが良さそう?
- 現在のスケジューラは割り込み時のカーネルモード(CPL0)で稼働し、CS,CR3,SPレジスタ等を切り替えている。
- ここでCSの下位2bitに3を仕込んだプロセスを仕込んでおけば次回スイッチ時にCPL3のプロセスが稼働しそう
- スケジューラはプロセス構造体の双方向リンクリスト(run_list)を順番に切り替えるだけの物を書く予定
2. プロセスはCPL3で動作し、割り込みが発生した時にはCPUが自動的にCPL0にしてくれるのか?
- 「はじめて読む486」ではTSSを前提にしているので参考にならず
- インテルマニュアル第3巻を見る
- 5-18に、特権レベルの高いプロシージャに割り込む場合の事が書いてる
- スタックのセグメント・セレクタとスタックポインタが現在実行中のタスクのTSSから取得されるとあるが、TSSを使わない場合はどうするんだろう。
- TSSを設定していないので現在のTRレジスタに登録してある値からでたらめなメモリ領域を参照しに行く?
- でたらめな値をCPUに設定された後に改めてSS,ESPを設定すればいいかな?
- 動作的にはスタック使う前に適切な値がSS,ESPに設定されていれば何の問題も無さそう
3. 各ユーザプロセスがカーネル部分を実行時のスタック領域をどうするか
- ユーザプロセスがシステムコール等を発行したときに、割り込みが発生しカーネル部分が実行されるが、その際切り替えるべきSS,ESPはどうする
- SSはフラットモデルを使うので全て共通
- ESPはプロセス生成時にそのプロセス専用のスタック領域をカーネル領域上に確保(0xC0000000〜の領域のどこか)する必要がある。
- Linuxでは8KB分用意し、task_struct構造体と共用している。
- alignは0x1000であわせる必要がある。(12KB分メモリを確保しalign)
4. 最初のユーザプロセスをどうするか
- ファイルで用意する。
- システムコールのみを使った短いテスト用コードをアセンブラで書いておく(int 0x80等)
- テスト用システムコールを用意する(vgaへのprint等)
- elf等のメモリマップは一切考えず、ファイルの.text領域を仮想メモリの0x0に置き、.rodata .dataなどは0x8000000等に置くこととする。
- 最初はセクションの判定を考えるのも煩わしいのでファイルの0x100からを.data領域とするなどの決め打ちとする。
- プロセスのスタック領域は0x80000000から下の領域とする
- ヒープ領域はひとまず考えない
5. ユーザプロセスのページングをどうするか
- 0x0から4KBalginで.text部分を物理メモリと関連付け
- 0x80000000の前後数KBを物理メモリと関連付け
- 物理メモリの先頭64MBはカーネルが使用してるからそれ以降からプロセス作成時にkallocし割付