30日でできる!OS自作入門パート10(15日目①)

気がつけば1カ月ほど空いてしまいましたがまだ終わっていません。ということで続けていきます。

今回のサブタイトルは『マルチタスク-1』です。

 

マルチタスクをCPUにさせるには?


実はCPUが1つしかなくてもマルチタスクはできているようです。その場合同時に複数のプログラムを動かしているのではなく、忍者の分身の術のようにAのプログラムを少し動かして次にBのプログラムをちょっと動かして…と処理しているようです。そうなるとこの切り替えを高速にしないと同時に動かしているように見えないですね。このプログラムの切り替えを「タスクスイッチ」と言うようです。

CPUにタスクスイッチをしなさいと命令するとCPUはレジスタの値をすべてメモリに書き込みます(後で実行を再開するため)。その後にこれから実行するプログラムのためにメモリから全部のレジスタの値を読み込みます。これで切り替えは完了となります。

 

レジスタの内容はどのようにメモリに書き込まれるのか?


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;
};

このコードはTSS(タスク状態セグメント)というものでこれをつかってレジスタの内容をメモリに書き込みます。TSSはintが26個集まったもので全部で104バイトです。

1行目はタスクの設定に関する内容、2行目は3bitのレジスタ、3行目は16bitのレジスタです。4行目のldtrとiomapは1行目と同じくタスク設定に関する部分です。

 

タスクスイッチしてみる


ということでタスクスイッチをしてみます。タスクAとタスクBを準備してAからBへ切り替えます。まずはTSSを二つ作る必要があります。

メインクラスにTSSの呼び出しを書き、ldtrとiomapに適当な値を代入します。

// 呼び出し
struct TSS32 tss_a, tss_b;    

// tss_aに値を代入
tss_a.ldtr = 0;
tss_a.iomap = 0x40000000;
// tss_bに値を代入
tss_b.ldtr = 0;
tss_b.iomap = 0x40000000;

// GDTに登録(tss_aをgdtの3番目、tss_bをgdtの4番目に設定)
struct SEGMENT_DISCRITPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT;
set_segmdesc(gdt + 3, 103, (int) &tss_a, AR_TSS32);
set_segmdesc(gdt + 4, 103, (int) &tss_b, AR_TSS32);

 

ここまで出来たら実際に切り替えをします。

続きは次回


マルチタスク-1はここでまだ半分です。なかなか手強いので15日目は2つにわけたいと思いますので今回はここまでです。

 

スポンサーリンク

30日でできる!OS自作入門パート9(14日目)

結構長くやっているつもりですが、まだ9回目の投稿なんですね。

というわけで今回のサブタイトルは『高解像度・キー入力』です。

一通りの説明は終わったらしい


ここまで色々と機能を実装してきましたが、ここまででプログラミング言語の知識やアルゴリズムのテクニックの紹介は終わりのようです。これからは今までの知識の組み合わせでOSが作れるとのこと。

なので筆者の気分は「明日から本気だす」状態のようですが、それで終わりだと読者はつまらないだろうということで高解像度とキー入力の機能を実装するようです。

画面のサイズを大きくする


高解像度にするとはなんぞや?ということですが今までの320×200の画面サイズを640×480にするようです。

具体的にはアセンブラの画面モード設定を書き換えます。

BX,0x4101

AX,0x4f02

こう設定されていると画面が大きくなります。

この値を説明すると、昔ビデオカード会社が作ったVESAという協会が共通の設定方法で専用のBIOSを作りました(VBE)。AX=0x4f02とするとVBEを使った画面モード切替となり、BXの値に画面モード番号を設定します。0x101というのが640×480×8bitカラーの設定値で、この値に0x4000を足した値をBXに入れると640×480の画面サイズになります(だから0x4101が設定されている)。

ちなみに実機で試す場合はどんなビデオカードを使っているかによります。たとえばVESAに協力していない会社のビデオカードの場合だとVBEモードに設定できないのでデフォルトの320×200で我慢するしかないようです。

 

キー入力


Aのキーを押すとAを押した時は1Eと表示されはなすと9Eと表示されます。

なんでかよくわかりませんがそれぞれのキーで決まった値が表示されるのでこれを正しく直します。

といってもちょっとこの辺はよくわかりませんでした…。なのでちょっと調べて自分なりに理解してみたいと思います。

 

最後に


ちょっと中だるみっぽくなってきてしまっています。

今回はちょっと息抜きくらいの感じでしたが結構理解が追いついていないです。

次回までにちょっと復習をしたいと思います。

スポンサーリンク

30日でできる!OS自作入門パート8(13日目)

今回のテーマは『タイマ-2』ということで12日目の続きになります。

30日のうち2日もタイマに費やすとは長くないか?と思いましたが、どうやら今後タイマをよく使うらしくそのためしっかり作りたいようです。同じような理由でレイヤーの制御(本書では下じき制御)も頑張っていたそうです。

タイマ2となっていますが、今回はここまで書いたタイマ機能の改良になります。繰り返し出現するコードを共通化してまとめたり、if文の判定を改良したりそういう修正です。

ただ修正して「なんとなく早くなったかなー」では自己満足になってしまうので性能を数値として性能を測定してみます。

性能測定


やり方は簡単でまず修正前のソースでカウントを実行して10秒経ったらどれだけカウントできたか確認するという方法です。修正前と修正後でそれぞれ5回実行して平均を見てみました。筆者は最初エミュレータで実施しましたが5回の中でも結構誤差があったため実機でも試していました。エミュレータでの最大値と最小値の差は10575であったのに対し、実機は177なのでかなり違いました。

結果、修正前の平均は74643595に対し修正後の平均は74619985ということで23610だけ速いということになりました。はい。

さらに改良


さてさらに改良していきます。FIFOバッファを見直したり番兵とよばれるリストの終端を表す仕組みを取り入れたりしました。

バッファや割り込みを改良したことで先ほどの値より1.3~1.7倍ほど数値はよくなりましたが番兵を使ってもあまり変化がなかったことが筆者は不満なようです。確かにこの仕組みを取り入れると無駄がなくなるのでよさそうな感じですがなぜでしょう?ということで今回は終わっております。

終わりに


自分で作ったソースを改良するというのは仕事でプログラミングをしているときも作りながらよく考えますよね。プログラムを改良することに一生懸命になってしまい納期がギリギリになってしまうこともありますがそれだけ楽しい作業だし改良してすっきりしたソースになるととても満足します(自己満足ですが)。

このように開発作業を読んでいるとやはり自分でも作ってみたくなりますね。最後まで読んで自作OSを自分で始めから作ってみたいです。

スポンサーリンク

30日でできる!OS自作入門パート7(12日目)

今回のサブタイトルは『タイマ-1』ということでやっていきます。

始めはタイマがいかに重要かが書いてあります。windowsの場合右下に時計が出ていると思いますが、それだけでなくCPUの割り込み時間の計算や時間の管理が出来ません。ということでタイマを使います。

PCでタイマを使うには『PIT』という装置を設定すればいいようです。PITとは『Programmable Interval Timer』の略で設定可能な間隔型タイマという意味らしいです。ようするに何秒ごとに割り込みを起こしてもらうか決められるようです。PCではPITがIRQの0番に繋がっているのでPITを設定することでIRQの割り込み間隔を設定できるということです。ちなみにPITはチップセットの中に集積されているようです。

PCは8254というチップが使われていて、そのチップの資料を調べて設定方法を確認します。その設定に応じたコードを書いていきます。

この辺りは載っているコードを見ていただくとわかりやすいと思うのですがここに載せていいのかちょっとわかりませんのでいつものように割愛いたします…。

 

その後タイムアウト機能を実装したところで恒例の改善です。割り込み処理の間隔が長いので短くしていきます。割り込みが長いと本処理が突然止まったりしてよくないようです。そして次回もタイマの話です。

終わってみて


なんか今回もざっくりした内容になってしまいました。

プログラマーなら言葉で説明するよりコードを見ればいっぱつで理解できるというのも多いとおもいます。しかし本に掲載されているコードをブログに載せるのはあまりよくない気がして文章ばかりになっております。検索すると自作OS本に掲載されているコードを載せているブログもあるのでそちらの方が参考になるかもしれないですね…(笑)

結局自分が理解できていればいいのですが中々難しいので全部理解できないまま進んでいます。とりあえず一周読んだらもう一度読み返す予定なのでこんな感じで進んでいきたいと思います。

スポンサーリンク

30日でできる!OS自作入門パート6(11日目)

11日目のサブタイトルは『ついにウインドウ』になります。といっても始めは恒例になってきたちょっとした改良からです。

相変わらずマウスが続きますが、今回の問題は画面端までマウスが隠れないというものです。試しにパソコンでこのブログを見ているかたがいましたらマウスを端までもっていってください。マウスが隠れたと思います。しかしハリボテOSではマウスが隠れず画面に残ったままです。

なぜこうなっているかというと、プログラム上で画面外に出たときにもきちんと表示されるよう制御している関数が書き換え直しているからですね。ということで範囲外にはみ出したら補正するようにソースを書いてこの問題は解決です。そこからちょこちょこ筆者の好みに合わせてプチ修正が入り、いよいよ本題のウインドウです。

ウインドウを出してみよう


早速表示するためのウインドウの絵を描きます。ウインドウ用の関数を作り、そこにソースを書いていきます。そしてその関数を呼び出せるようメインメソッドを修正して無事に表示されました。意外とあっさりです。

ちょっとここでまたしても問題が。どうもこのウインドウ、ちらちらしてしまいます。10日目の時にレイヤー構造で表示しているという話をしましたが、どうやら背景の範囲のレイヤーを描いてからウインドウを描くのが原因のようです(よくわかりませんが)。ということでまたしても修正です。

そんなこんなで直ったと思ったらマウスを重ねるとちらちらしたり、また直したと思ったら今度はマウスだけちらちらしたり色々試行錯誤を重ねて最終的にはちらちらしなくなりました。めでたしめでたしですね。

終わりに


マウスとウインドウと画面表示系の話が続いています。トライアンドエラーを繰り返しながら少しずつ進んでいますね。

何かを作っているとまぁいっかでなんとなく終わらせることもあるのですが(今回でいうと画面端でマウスが消えない問題とか)きちんと修正しているのでそういう姿勢は見習わなければいけないと思いました。

それにしても最近はあまり進んでいない気がするのですが、本当に30日である程度完成するのでしょうかね?

スポンサーリンク