みかん本輪読会 24章 複数のターミナル
ターミナルを増やす p.560 - 15章でターミナルを作った - けど同時起動は出来なかった → 今回は複数のアプリを同時に起動させるのが目標 - アプリの起動方法はTerminal::ExecuteFile()の中で ELFファイルをメインメモリに読み込んでいる
F2を押してターミナルを生成する p.560~561 - リスト24.1のようにF2キーを押すとターミナルクラスを 新規に生成するコードを追加してみる - 図24.1のように2つ目のターミナルが開いた リスト24.1 - でも2つ目のターミナル のカーソルが点滅してない - 他にも例外が発生する → 不具合に対処する
カーソル点滅を自分で p.561 - 今のカーソル点滅の仕組みは、メインタスクが管理するタイ マがタイムアウトした時に、そのタイムアウトメッセージを ターミナルタスクにコピーして送信することで実現している - この仕組みではターミナルが増えた時にどのターミナルへ メッセージを送るかをメインタスクが判断する必要があり、 コードが複雑になる - ターミナルが非アクティブでもカーソルが点滅する
カーソル点滅を自分で p.561~563 - ターミナル自身がカーソル点滅を制御する - ターミナルタスクが起動すると独自にタイマ計測 - ターミナルクラスがウィンドウのアクティブ/非アクティ ブを検知できるようにし、状態をメッセージタスクに送 信することで非アクティブ時のカーソル点滅をなくす (リスト24.2~24.5)
複数アプリの同時起動 p.564~565 - 複数のアプリを同時起動すると例外が発生する → 仮想メモリ領域が競合するから (19.2 参照) → 対策のために階層ページング構造の切り替えを行う - アプリは専用の階層ページング構造を持ち、アプリを切 り替える際はCPUが参照する階層ページング構造の切 り替えも行う (図24.4)
複数アプリの同時起動 p.564~566 - 階層ページング構造の最上位データ構造はPML4 - CPUのCR3レジスタがPML4の物理アドレスを保持し て仮想アドレスと変換する (19.3 参照) → アプリ毎にPML4を最上位とする階層ページング構造 を持たせて、アプリ切り替え時にCR3レジスタを書き換え る
複数アプリの同時起動 p.566~567 - リスト24.6で実行可能ファイルをロードする前に PML4を設定する - リスト24.7で新しいPML4を構築して有効化する → PML4として用いるデータ構造を生成し、OS用のペー ジマップ設定をコピーし、構築したPML4をCR3と現在の タスクの設定する
複数アプリの同時起動 p.567 - リスト24.7ではコピーするPML4の要素数が256個 - PML4の全体のサイズは64ビットx512なので半分 - PML4は前半がOS用、後半がアプリ用となっている - OS用のメモリマッピングは全てのアプリで共通なのでそ のままコピーできるPML4をCR3及び現在のタスクに設 定することでSetupPML4()の処理は完了 - 新しいPML4でアプリの実行ファイルをロードする
複数アプリの同時起動 p.568 - リスト24.8でアプリ終了時の処理を行う - CleanPageMaps()でPML4より下の階層ページング 構造を削除 - 今までのPML4はOS用として作り、使いまわしていた ので削除は不要だったが、アプリ用に生成したPML4 では削除する必要がある
複数アプリの同時起動 p.568 - リスト24.9ではタスク構造体からPML4の登録を解除し、 CR3をリセットしてOS用のPML4を指す処理を作る - タスク構造体から登録を解除する処理とCR3のリセット処理 の順番は大事 → 逆になるとタスクが戻ってきた際にタスク構造体にはまだ有 効なPML4が設定されており、そのPML4がCR3に設定されてし まうのでCR3をリセットする意味がなくなる - リスト24.10ではCR3にPML4を設定する処理を実装
ターミナルなしのアプリ起動 p.571 - 今まではターミナルを起動してアプリを起動してた → アプリを立ち上げるだけで大量のターミナルが… - ただアプリの起動はターミナルに依存しているのでター ミナルなしではなくターミナルを見えなくする方向で実装 する - リスト24.13ではnotermコマンドを新たに作成
ターミナルなしのアプリ起動 p.571~574 - notermコマンドで起動したターミナルは図形描画(リ スト24.15)、画面表示(リスト24.16)、カーソル表示(リ スト24.17)、ウィンドウ表示(リスト24.18)がされずに 起動する
OSを守ろう p.575 - 今のMikanOSではアプリがCPU例外を発生させると 例外ハンドラが呼び出され、OSがフリーズする - バグを完全に無くすことは難しいのでアプリが例外を 発生させてもOSがフリーズしない仕組みを作る
OSを守ろう p.577 - 例外発生させたアプリを特定して強制終了させる - 例外発生がOSかアプリかは割り込み発生時のCSレジ スタの値で判別可能 - CSの下位3ビットはCPLフィールドでCPUの動作権限を 表し、OSは0アプリは3になる → CPLの値が3ならばアプリを終了させる
OSを守ろう p.579 - リスト24.20はExitApp()によってアプリを強制終了さ せている - リスト24.21はExitApp()を利用したKillApp()とそれを 呼び出す例外ハンドラの実装 - CPL=3であればExitApp()でアプリを強制終了 - ExitApp()を呼ぶ前にsti命令でIF=1に設定する → 次の割り込みや例外が受け付けられるように
アプリを起動してから強制終了まで p.579 1. CallApp()によりアプリが起動、PSPにアプリ用スタッ クが設定され、CSはアプリ用(CPL=3)になる 2. アプリがCPU例外を発生させる 3. CPUはIDTを調べ適切な割り込みハンドラを呼び CPUはCSにOS用の値を、IFビットに0を設定する 4. 割り込みハンドラはKillApp()を呼び出す。CPL=3より アプリ実行中の例外と判断される
アプリを起動してから強制終了まで p.579 5. stiによりIF=1となり、次の割り込みが許可される 6. KillApp()はExitApp()を呼び出す。ExitApp()はRSP及 び各レジスタをOS用に復元し、CallApp()の次の行にジャ ンプする
OSを守ろう p.579~580 - フラットバイナリ形式のアプリ実行機能を削除 → CPL=0 つまりOSモードのまま実行するので今回実装 した保護機能が働かない - ELF形式に対応しているので対応する必要がない