読者です 読者をやめる 読者になる 読者になる

趣味プログラマによるOSS開発日誌

趣味で作っているOSSソフトウェアの紹介や関連技術の紹介、楽曲製作、Webデザイン勉強状況を紹介します。

TSSを使用しないコンテキストスイッチ

30日本とか、はじめて読む486とかで紹介されているコンテキストスイッチ(タスクスイッチ)は、TSS(タスク状態セグメント)を利用した方法である。
しかしここ2週間、TSSを用いたコンテキストスイッチがどうもうまく行かないので、別の方法を試みた・・・というよりは、迷っている間に自前で用意できそうな気がした。
ちなみに、LinuxもTSSを用いたコンテキストスイッチを行っていないことから(アーキテクチャへの依存性などを考慮しているため)、TSSを使わないコンテキストスイッチで実装することは、よい勉強になるのではないと思う。

で、実装できたのでここで書いてみる。

TSSを用いないコンテキストスイッチを行う方法は、以下のようになる。

  1. 前タスクのレジスタ(汎用レジスタ、EFLAGS)の退避
  2. 前タスクのスタックポインタ(ESP)の退避
  3. 前タスクのプログラムカウンタ(EIP)の退避
  4. 次タスクのスタックポインタ(ESP)の設定
  5. 次タスクのプログラムカウンタ(EIP)へジャンプ
  6. 次タスクのレジスタ(汎用レジスタ)の設定

具体的なソースコードを示すと、次のようになる。
ソースコードintel記法とする。

# 前タスクのレジスタの退避
	pushad
	pushfd
	mov [前タスクのスタックポインタの保存先], esp
	mov [前タスクのプログラムカウンタの保存先], restore
# 次タスクのレジスタの設定
	mov esp, [次タスクのスタックポインタの保存先]
	jmp [次タスクのプログラムカウンタの保存先]
restore:
	popfd
	popad

基本的にスタックにレジスタを保存させることで、コンテキストスイッチを実現している。
ここで気をつけなくてはならないのは、前タスクのプログラムカウンタの保存先をrestoreラベル(jmp命令の次のアドレス)にしているところである。
このようにすることで、次に前タスクに処理が戻ったときに、popfdからスタートさせることができる。

まだ不十分のところがあるが、githubに自作OSの最新のソースコードを置いた。
https://github.com/nutti/Educational-Operating-System/blob/master/src/asm_util.s
switch_task_2というラベルが、今回話題にした部分である。

実行結果以下に示す。・・・といっても画像なので、マルチタスクが動作しているようには見えないが。

[参考資料]
Linuxカーネルソースコード(バージョン2.6.15のinclude/asm-i386/system.hにあるswitch_toマクロ)
http://d.hatena.ne.jp/naoya/20070924/1190653790