OS自作本 MacOS 4-6日目

やったこと

画面の色と画面上のテキストとキーボードとマウス

メモリ復習

ipl10.nas 終了時
アドレス 内容
0x07C00ー0x07DFF IPL。フロッピーの先頭1セクタ(ブートセクタ)
0x08200ー0x34FFF フロッピーの内容(10シリンダ分。IPLを除く)
OS実行時
アドレス 内容
0x00000000ー0x000FFFFF 起動中にいろいろ使うけど、その後は空き(1MB)
(0x000A0000ー0x000AFFFF) VRAM(画面用メモリ) 64KB
0x00100000ー0x00267FFF FDの内容記憶用(1440KB)
0x00268000ー0x0026F7FF 空き(30KB)
0x0026F800ー0x0026FFFF IDT(2KB)
0x00270000ー0x0027FFFF GDT(64KB)
0x00280000ー0x002FFFFF bootpack.hrb(512KB)
0x00300000ー0x003FFFFF スタックなど(1MB)
0x00400000ー 空き

画面上の色(P.84, 85)

1. 色の登録(init_palette関数)

8bit color modeなので256色使えるが、使いそうな16色を登録することにする。 まず16*3のテーブルを作り、そこにそれぞれの色のRGBの値を順番に入れていく。 例えば、1番目の色を#ffffffにしたいのなら、0xff, 0xff, 0xffと入れていく。 この時、static char tableとしてtableを作成することで、アセンブラに翻訳した時にRESBではなくDBでメモリに書かれるため早いらしい。

2. 登録した内容をデバイスに送信(set_palette関数)

CPU外のデバイスに送信するので、割り込みの作業が必要。デバイスに送信する際は、io_out8というnaskfunc.nasで実装されている関数を使う。

3. VRAMメモリをいじる

VRAM(画面用メモリ)の値を適切な色に変更する。これはポインタを用いればCで実装可能。

画面上のテキスト(P101,102)

1. 文字の登録

16*8のテーブルに文字の形を登録する。 マウスカーソルも同様。

2. 文字の利用(putfont8関数)

f:id:lagomnist:20190115231455j:plain
putfont8関数

キーボードとマウス(P.115)

1. GDTとIDTの初期化&設定

GDT : Global (Segment) Descriptor Table = セグメントの情報が詰まったテーブル

IDT : Interrupt Descriptor Table = 割り込みの情報が詰まったテーブル

これらはどちらもCPUの設定だが、これをまず初期化&設定しなければならない。

セグメントとはプログラムごとに使っているメモリのこと。それらが競合しないためにGDTが存在している。 GDTには各セグメントの大きさ、開始番号、その特性が書かれている。 そのプログラムがどのセグメントに対応しているのかを表す、セグメントレジスタというレジスタが存在しており、MOV AL [DS:EBX]という命令をすれば、自動的にEBXにそのセグメントの開始番号DSを足したところのメモリを読んでALに代入してくれる。ちなみにセグメントレジスタは16bitであり、下3bitが使えないので、結局13bit=8000個のセグメントしか利用できない。そして一つのセグメント情報は8byte必要なので64KBのメモリが必要。そしてセグメント(CPU全メモリを表しているセグメントとbootpack.hrb用のセグメント)情報をGDTに入れた後、GDTR(Global (Segment) Descriptor Table Register)という48bitのレジスタに、先頭セグメントの番地と有効設定個数(大きさ)をLGDTという命令を使って入れる。MOV命令ではなく、LGDT命令を用いるのは、48bit=6byteという特殊なレジスタだから。ちなみに48bit中、上位32bitは番地、下位16bitはリミット(GDTの有効バイト数-1)が入っている。GDTの初期化以上。

IDTは、各割り込みとそれに対応する関数の表である。「X番が発生したらY関数を呼び出す」ということが表を見たらわかるようになっている。割り込みが発生した時にまずやらないといけない処理は、割り込みハンドラ処理。簡単にいうとレジスタをメモリに退避して、割り込み処理を呼び、レジスタを復帰させIRETD命令を実行するという流れ。キーボード割り込みによって発生するレジスタ退避&復帰処理は、naskfunc.nasのasm_inthandler21に書いてあり、実際の割り込み処理はint.cのinthandler21に書かれている。C言語レジスタ退避&復帰を書かない理由は、最後のIRETD命令でのリターンがCでは書くことができないかららしい。IDTの設定の後に、PIC(Programmable Interuppt Controller)の初期化もしなければならない。これは、PICは8個の割り込み信号IRQ(Interrupt Request)を1つの割り込み信号にまとめる装置で、これを二つ使うことによって15個の割り込み信号を可能としている。

f:id:lagomnist:20190116003354j:plain
PICの初期化の内容

これらの最後にCPUの割り込み設定を許可する(io_sti関数)

以下がbootpack.cのHariMain内のソースコード

init_gdtidt(); GDT, IDTの初期化&設定
init_pic(); PICの初期化&設定
io_sti(); /* IDT/PICの初期化が終わったのでCPUの割り込み禁止を解除 */

めっちゃ疲れたけど頭に内容が入ったので楽しい。