Yabu.log

ITなどの雑記

30日OS自作本15日目

15日目はマルチタスク(タスクスイッチ)をやりました。

マルチタスクp290~310

  • CPUは複数のタスクを同時に実行することができない。タスクをそれぞれ少しずつ実施すること実現できる。
  • そのための仕組みがタスクスイッチ
    • レジスタの内容を全て保存する
    • ジャンプ命令でタスク間を移動
  • TR(task register)に現在のタスク番号を格納する

これを短い期間で繰り返している。

タスクスイッチ

保存するレジスタ等の内容

TSS(task status segment)という種類のセグメントを利用します。 int型のメンバが26個ありますので、保存するレジスタ等の情報は全てで26*4=104バイトの領域が必要です。

struct TSS32 {
    int backlink, esp0, ss0, esp1, ss1, esp2, ss2, cr3;
    int eip, eflags, eax, ecx, edx, ebx, esp, ebp, esi, edi;
    int es, cs, ss, ds, fs, gs;
    int ldtr, iomap;
};

こちらをGDTに登録し、タスクスイッチのたびにロード、セーブという具合です。

  • 1段目int backlink, esp0, ss0, esp1, ss1, esp2, ss2, cr3;レジスタの情報ではありません

JMP命令とEIPレジスタ

  • 次の命令の実行場所はEIPレジスタに保持して管理されている
  • JMP命令というのは実施MOV EIP,<JUMP先アドレス>と同じ意味
    • ただしアセンブラでEIPに直接代入できない。
       - だから素直にJMP命令を使いましょう。
      

JUMP命令のnearモードとfarモード

  • 命令の読み込み位置はcsとeipによって決まる
  • リアルモード時はcs*16+eipで表現。
    • csはセグメントのベースアドレス、eipはオフセットアドレスの意味になる。
  • プロテクトモード時のcsの挙動の理解が曖昧。

実行イメージ

taskA実行中にtaskBに切り替える例で説明されています。 1.TSSをtaskA,taskBで用意

struct TSS32 tss_a, tss_b;

2.tss_bのeipにタスクとなるプログラムを設定

(関数ポインタは初見?な気がするが特に説明なし?)

void task_b_main(void)
{
    for (;;) { io_hlt(); }//HLT命令。何もしない。
}
tss_b.eip = (int) &task_b_main;

3.GDTにTSSを登録設定

set_segmdesc(gdt + 3, 103, (int) &tss_a, AR_TSS32);
set_segmdesc(gdt + 4, 103, (int) &tss_b, AR_TSS32);

4.10秒のカウント表示時に同時にタスクスイッチ命令

} else if (i == 10) { /* 10秒タイマ */
    putfonts8_asc_sht(sht_back, 0, 64, COL8_FFFFFF, COL8_008484, "10[sec]", 7);
    taskswitch4(); //コレ!!!!!

5.アセンブリに定義したタスクスイッチ関数を実行。 ここでfarモードでジャンプ。

_taskswitch4:  ; void taskswitch4(void);
        JMP     4*8:0
        RET

コレで3.で登録したGDT+4(task_b)の位置にJMP。この時、ジャンプ先のセグメントが実行可能セグメントではなく、 TSSなのでCPUはEIPやCSを書き換えずにタスクスイッチ命令だと解釈し、TSSで指定したタスクに変わるらしい。

※本章では以後決め打ちになっているタスク名やアドレスは関数の引数にして汎用的なタスクスイッチ処理に作り変えられる。

動画

上記のプログラムを動かした動画。10秒経過の次の瞬間にHLT命令が実行されマウス操作が受け付けられなくなっている。*1

www.youtube.com

感想

CPUがマルチコアだとどうなる?とか、Javaでマルチスレッドなプログラミングを行った時にCPUレベルではどのように動く?などまだまだイメージできないことは多いですが、

この辺の違いを意識していこう。

30日でできる! OS自作入門

30日でできる! OS自作入門

*1:マウスの割り込み操作は多分受け付けているが描画処理が実行されていない。