自作OSに挑戦する日記 1日目

 「30日でできる!OS自作入門」を読んで分かったことや、とりあえず書いておきたいことなどを書いていきます。
 この本はChapterが1から30まであるので、各チャプター毎に1記事書いていきます。

Chapter 1 「PCの仕組みからアセンブラ入門まで」

今回やった内容

  • バイナリを写経して「hello, world」を表示するようなOSを作る
  • アセンブラを写経して「hello, world」を表示するようなOSを作る

環境

作業記録

 まずは本に書かれているバイナリを写経します。

f:id:guguru0014:20190115225043p:plain
バイナリ写経

 書き上げたバイナリを「(任意の名前).img」として保存します。僕は本の通りに「helloos.img」にしました。
 次に、作成したimgファイルをUSBに焼きます。仮想環境で実行するという選択もあるのですが、自分のこだわりで実機で動作させたかったのでこうしました。

// USBが刺さっているポイントを確認(dev/diskNを確認する)
diskutil list

// アンマウント
diskutil unMountDisk /dev/diskN

// 書き込み
sudo dd if=/path/to/img/helloos.img of=/dev/diskN

 USBに書き込む事ができたら、PCにUSBを刺して、BIOSから起動するディスクを設定。すると…

やった!!自作OSが起動しました!
「hello, world」が表示されるだけのOSですが、自分の作ったのがちゃんと動作してるのを見るとなんか感動します。


 バイナリを直接書くのもなんとなく楽しいですが、ずっとこのままでは辛いという事で、アセンブリ言語を使って書いていきます。僕にとっては人生初アセンブリです。

 本の通りに写経します…。そして、写経したものをコンパイルします。本では、著者の方の自作コンパイラを使う方法が書かれていますが、macに対応していないので「nasm」を使うことにしました。

// コンパイル
nasm -f bin -o helloos_assembly.img helloos_assembly.asm

 この時、RESBの行でwarningが出ますが、これは無視しても良いみたいです。アセンブリ言語コンパイルについては以下のページを参考にしました。

d.hatena.ne.jp motojiroxx.hatenablog.com

 生成されたimgファイルを、先ほどと同じようにUSBに書き込んで起動すると、同じように「hello, world」が表示されます。

アセンブリ言語の命令についてのメモ1

  • DB
    • 「data byte」の略。1バイトだけファイルに書き込むという命令。
  • RESB
    • 「reserve byte」の略。指定バイト分0x00で確保する命令。

 先ほど書いたアセンブリはまだ意味不明…ということで、コメントを加えつつ理解できるような形で書いていきます。

; hello-os [30日 OS自作入門]

; FAT12ドライブのための記述
    DB  0xeb, 0x4e, 0x90
    DB  "HELLOIPL"      ; ブートセクタの名前。自由でいいらしい
    DW  512             ; セクタの大きさ。a絶対512
    DB  1               ; クラスタ(?)の大きさ。1セクタにしなければならない
    DW  1               ; FATがどこから始まるか。普通1セクタ目から
    DB  2               ; FATの数。絶対2
    DW  224             ; ルートディレクトリ領域の大きさ。普通は224エントリかららしい
    DW  2880            ; ドライブの大きさ
    DB  0xf0            ; メディアのタイプ。絶対0xf0
    DW  9               ; FAT領域の長さ。絶対9セクタ
    DW  18              ; 1トラックに何セクタあるか
    DW  2               ; ヘッドの数。絶対2
    DD  0               ; パーティションを使わない場合は0
    DD  2880            ; ドライブの大きさをもう一度書く
    DB  0, 0, 0x29
    DD  0xffffffff      ; ボリュームシリアル番号
    DB  "HELLO-OS   "   ; ディスクの名前。11バイト
    DB  "FAT12   "      ; フォーマットの名前。8バイト
    RESB    18

; プログラム本体

    DB  0xb8, 0x00, 0x00, 0x8e, 0xd0, 0xbc, 0x00, 0x7c
    DB  0x8e, 0xd8, 0x8e, 0xc0, 0xbe, 0x74, 0x7c, 0x8a
    DB  0x04, 0x83, 0xc6, 0x01, 0x3c, 0x00, 0x74, 0x09
    DB  0xb4, 0x0e, 0xbb, 0x0f, 0x00, 0xcd, 0x10, 0xeb
    DB  0xee, 0xf4, 0xeb, 0xfd

; メッセージ部分
    DB  0x0a, 0x0a       ; 改行2つ
    DB  "hello, world"
    DB  0x0a             ; 改行
    DB  0

    RESB 0x1fe-($-$$)         ; 0x001feまでを0x00で埋める命令

    DB  0x55, 0xaa            ; これがセクタの最後に置かれていないとブートセクタとしてみられない(!)

; ブートセクタ以外の記述
    DB      0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00
    RESB    4600
    DB      0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00
    RESB    1496432

 本ではフロッピーディスク向けと書かれていますが、USBに書き込んでも普通に動作しました。
 プログラム自体に引っかかるようなポイントはなかったのですが、コメントで「よく分からないけどこの値にすれば良いらしい」という文があり、ちゃんと説明してほしいなぁ〜という感じにはなりました。
 写経する際の注意点としては、メッセージ部分のRESB 0x1fe-($-$$)です。本だとRESB 0x1fe-$になっていますが、これは著者の方の自作コンパイラ用の書き方で、nasmだとエラーになります。

 PCが起動するとき、まずは指定ディスクの最初のセクタを読みます。その時、セクタの最後に55 AAがあればそれをブートセクタと認識して起動処理をかけます。この55 AAは必ずセクタの最後(510バイト目)になければならないのですが、プログラムを書くたびに位置を調整しているととても面倒です。
 そこで、RESB 0x1fe-($-$$)を使います。$は文が先頭からどのくらいの位置にあるかどうかを表す変数で、'$$'はそのセクションでどの位置にいるのかを表す変数です。つまり、0x1feバイト(510バイト)からその文が何バイト目にあるかを計算して指定バイト分確保することで、55 AAの調整をしなくて済むわけです。

 このアセンブリコンパイルして、USBに書き込むことで「hello, world」OSが完成です!

アセンブリ言語の命令についてのメモ2

  • DW
    • 「data word」の略。1ワード分ファイルに書き込むという命令。1ワードは2バイト。DBの仲間。
  • DD
    • 「data double-word」の略。2ワード分ファイルの書き込むという命令。2ワードは4バイト。DBの仲間。

 ただ「hello, world」を表示するだけでは流石に感動も薄れてきたので、好きな文字を表示するようにしてみました。

まとめ

 自作OS入門1日終了です!まだ1日目ということで、そんなにつまづかずに進めれたので良かったです。やはり、自分で書いたOSが動作しているのを見ると感動します…すごい…。