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の割り込み禁止を解除 */

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

OS自作本 MacOS 1-3日目

めちゃめちゃ重要なこと

HexからBinary変換

  • Hexの各桁がBinaryの4桁になる
  • 0xffff -> 1111 1111 1111 1111
  • 2の16乗 - 1 ≒ 2の16乗 = 64 * 1024 = 64KB

BinaryからHex変換

  • Binaryの4桁分をHexの1桁にする(逆の作業)

この計算を一瞬でできるように!

全体像

細かいところの説明が多く、OS開発の全体像が見えず嫌になっているので、先人たちのまとめをみながらじっくり整理して理解していく。

『30日でできる!OS自作入門』のメモ

このサイトに書かれていることがとてもわかりやすい。

はりぼてOS起動までの流れ

  1. 電源ON
  2. BIOS起動
  3. BIOSフロッピーディスク(以下FD)の先頭1セクタ(IPL)をメモリ(0x7C00~0x7dff)に読み込む
  4. IPLがFDから10シリンダ分をメモリ(0x8200~0x34fff)へ読み込む
  5. OS本体の起動準備(画面モード設定・1MB以上のメモリにアクセスできるようにする・32ビットモードに移行など)
  6. bootpackを用意してあるセグメントにコピーして実行
  7. はりぼてOSの処理

https://wa3.i-3-i.info/word15562.html http://www.cqpub.co.jp/interface/sample/200511/if0511_chap1.pdf

OS 30日本に書かれていることは、これらのWebsiteに書かれていること(PCの電源を入れてからOSが起動するまでの流れ)と合致している。

その他

以下は『30日でできる!OS自作入門』のメモから勝手に使用させていただいています。

ソースコードの役割

対応するソースコード
番号 対応するソースコード
4 ipl10.nas
5,6 asmhead.nas
7 上記以外のbootpack.cやsheet.cなど

asmhead.nasについて

asmhead.nasの処理については最初から理解する必要はないです。 本の中で徐々に解説されていきます。 asmhead.nasですでにメモリにロードされているFDの内容をまた別のところにコピーしているのは、 用意してあるセグメントに移すためと、P171のメモリマップに合わせるためという意図があるようです。

とりあえず、上記の

  • OS本体の起動準備(画面モード設定・1MB以上のメモリにアクセスできるようにする・32ビットモードに移行など)
  • bootpackを用意してあるセグメントにコピーして実行

がasmhead.nasの役割。bootpack.cにいろいろ書くことで、C言語を用いて開発できるようになっているのは、asmhead.nasにbootpack.cとのつなぎの部分が書かれているから。

フロッピーディスク

メモリマップ

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.63に書いてあるが、BIOSのページ (AT)BIOS - os-wiki

によれば

おまけ:一番簡単な画面モード0x13の使い方

このモードは解像度が荒いですが、パックドピクセルなのでとても簡単に扱えます。まず画面モードを切り替えて、そんでもってパレットを設定してしまいましょう。 VRAMは0xa0000~0xaffffの64KBです。厳密に言うと、320x200=64000なので、62.5KBですが。1ドット==1バイトですので、がしがしライトしてください。リードもOKです。たるいBIOSで1点ずつ描いていく必要はありません。以上!

と書いているので

上の

OS実行時
アドレス 内容
0x00000000ー0x000FFFFF 起動中にいろいろ使うけど、その後は空き(1MB)
(0x000A0000ー0x000AFFFF) VRAM(画面用メモリ) 64KB

となる

これからの開発の流れ

  • アセンブラでグローバル関数を書いてライブラリを自分で構築(naskfunc.nas)
  • それを利用しながらbootpack.cのHariMainに実装していく

疑問

  • p.40 「BIOSはPC基板上のRead Only Memoryにあらかじめ組み込まれている、基本的な入出力に関する関数の集まり」とあるが、PC基板上とはどこなのか。ハードウェアでどうやってそんな設計が可能なのか。

  • p.42 「0x00007c00-0x00007dffがブートセクタが読み込まれるアドレス」と書かれているが、これは全てのOSで共通していることなのか?qemuでOSを立ち上げているが、qemuにもこのようなメモリマップの設定がされてあるのか?またブートセクタでやらないといけないことは何なのか。

  • p.44 「Makefileを動かすようにするには、make.exeを呼び出す必要があります。」と書かれているが、macで実行する場合、make.exeは呼び出せない。macの場合のMakefileはどのように起動されているのか?またmake.batには以下のように書かれているが、%1 %2 %3 %4 %5 %6 %7 %8 %9パートは何の役割を果たしているのか?

..¥z_tools¥make.exe %1 %2 %3 %4 %5 %6 %7 %8 %9
  • p.52 バッファアドレスを決めるときに、「MOV AL [ES:BX]と書き、ES*16+BXのアドレスを指定することで、114095バイトまでメモリ番地を指定できるようになる」と書いてあるが、結局使うのが16マシンだったらES:BXの計算結果を使えないのではないのか?(結果を使うためにはどこかのレジスタかなんかに保存する必要がありそうなので)

30日OS本 macOS Mojave 環境構築

環境構築手順

github.com

このWebsiteを参考にして、環境構築してみると、make runで失敗してしまう。

cp helloos.img ../../z_tools/qemu/fdimage0.bin
make -C ../../z_tools/qemu
qemu-system-i386 -L . -m 32 -localtime -vga std -fda fdimage0.bin
qemu-system-i386: -localtime: invalid option
make[1]: *** [default] Error 1
make: *** [run] Error 2

のようなエラーが出てしまった。

解決法

上のWebsiteを最後までやったのち

github.com

から、z_tools_osxをダウンロードする。

z_tools_osxをz_toolsに名前を変更して、

HariboteOSディレクトリに置き、z_toolsを上書きする。

f:id:lagomnist:20190113015122p:plain
z_toolsを上書き

追記

3日目の最後の方でバグが生じるので、以下も変更しておいてください。

HariboteOS/z_tools/haribote/ の中にある、haribote.rulの中身の

../z_tools/haribote/harilibc.lib;
../z_tools/haribote/golibc.lib;

を以下のように変更する。

../../z_tools/haribote/harilibc.lib;
../../z_tools/haribote/golibc.lib;

完成!試してみる。

cd ~/HariboteOS/01_day/helloos0  
make run

f:id:lagomnist:20190113015426p:plain
おお!