ウォンツテック

そでやまのーと

OS作成

CPUのTSS機能を利用したタスク切り替えの考察

Kernelがタスク切り替えをした時、再びそのタスクに戻れるように現在のタスク情報をメモリに保存してから切り替える必要があるが、その保存情報がTSSである。このTSSのフォーマットはCPUにより決められており以下の物が格納されている。

・前のタスクへのリンク(前のタスクのセレクタ値)
※jmpでタスク切り替えした場合は要らないが、callや割り込み
でiretをした時に元のタスクに戻るために必要

・特権レベル0,1,2のスタックポインタ
 特権レベル0,1,2に移行した時にそれぞれのesp,ssを
 esp0,ss0,...esp2,ss2として保存しておく

・CR3レジスタ
 ページングを使用している時にそのページ・ディレクトリの
 ベース物理アドレスを保存しておく

・一般レジスタ群
 eip, eflags, eax, ebx, ecx, edx, esp, ebp, esi, edi
 es, cs, ss, ds, fs, gs

・LDTセグメントセレクタ
 このタスクが持つLDT(ローカルディスクリプタテーブル)の
 セレクタ値(LDTR)が入る
 ※LDTは各タスク毎に存在する。

・Tフラグ
 このビットをセットしタスク切り替えを起こすと割り込み
(割り込み番号1)が発生する。

・I/Oマップ・ベース・アドレス
 I/O許可マップへのTSSの先頭番地からのアドレス

TSSは実際にはGDTもしくはIDTに登録されており以下のようなフォーマットになっている

セグメントリミットはTSS(構造体)の大きさでベースアドレスはそのタスクのTSSの先頭アドレス。
タイプは4bitでBはビジーフラグの事でタスクが実行中もしくは実行待機中ならばセットされる。(jmp命令をした時にCPUが自動でセットしてくれる たぶん。。)

TRには現在のタスク番号(GDTやIDTの登録番号。0x28など)が保存されておりjmp命令などにより自動的にCPUが書き換えてくれる。ただし初期設定として一度だけTRを設定する必要がありアセンブラの「ltr」を使う必要がある。


全体の手順としては恐らく以下のような感じ
1. 各タスクのTSS(構造体)の設定
2.上記で作ったタスクのTSSをGDTに登録
3. 初期タスクのタスク番号をTRに設定
4. タスクのスイッチ(jmp命令等)