おりょうの寺子屋、教師兼生徒を務めますわたくし、
おりょうが、本日は出張授業ですよ~ なんちゃって。
#はじめに
HTC Advent Calendar 2020の14日目を担当します。
ONEJAPAN HACKATHONに参加したチームHTCのメンバー、おりょうです。
今回は私が絶賛挑戦中のOS作成の一部分を切り取ってご紹介しようかなと思います。
OSってみんな知ってるけどいざ作るとなるとなんだかハードルが高く感じますよね?
でも実際ちょっと興味ありません?
少なくともここまでの前説を読んでくれているあなたは、
少なからずOSに興味があるから見に来てくれているのでしょう。
そんなあなただけに今回は!
めちゃくちゃ簡単な「なんちゃってOS(ブートセクタ編)」をご紹介いたします。
合計3回に分けて紹介する予定です。
早速見ていきましょう!
##概要
成果物:OS(フロッピーディスクで、フォーマットはFAT12)
アセンブラ:NASK
想定対象読者:OS自作をこれから始めようとしている人。
##シラバス
1時限目:アセンブリ言語でソースコードを書こう①(ORG命令~entryラベルまで)
2時限目:アセンブリ言語でソースコードを書こう②(putloopラベル)
3時限目:アセンブリ言語でソースコードを書こう③(finラベル~msgラベルまで)←今日はここ!
4時限目:出来たソースコードを機械語にアセンブルしてみよう。
5時限目:PC/ATエミュレータを使ってOSを起動させてみよう。
#3時限目:アセンブリ言語でソースコードを書こう③
(finラベル~msgラベルまで)
まずは講義3回分のソースコードの全容を見てみましょう。
ORG 0x7c00
; 以下はFAT12フォーマットフロッピーディスクのための記述
JMP entry
DB 0x90
DB "HELLOIPL"
DW 512
DB 1
DW 1
DB 2
DW 224
DW 2880
DB 0xf0
DW 9
DW 18
DW 2
DD 0
DD 2880
DB 0,0,0x29
DD 0xffffffff
DB "HELLO-OS "
DB "FAT12 "
RESB 18
;ここからブートセクタについて書いていくで!
entry:
MOV AX,0
MOV SS,AX
MOV SP,0x7c00
MOV DS,AX
MOV ES,AX
MOV SI,msg
putloop:
MOV AL,[SI]
ADD SI,1
CMP AL,0
JE fin
MOV AH,0x0e
MOV BL,13
INT 0x10
JMP putloop
fin:
HLT
JMP fin
msg:
DB 0x0a, 0x0a
DB "hello, world"
DB 0x0a
DB 0
RESB 0x7dfe-$
DB 0x55, 0xaa
ざっと目を通しましたか?
それではさっそく説明開始!
##finラベル
今回はは残り2つのラベルについて見ていきます。
ここでは、文字を表示しきって、役割を果たしたOSちゃんに
お疲れ様の意を込めて休憩させてあげる処理を書きます。
fin:
HLT
JMP fin
これについては説明せずとも英語の意味からニュアンスは伝わるかと思いますが、
まずHLT命令によって、キーボードやマウスなどの操作をしない限りシステムを一時停止させる処理を書きます。
続けてJMP命令を使って、ジャンプ先をfinラベルに指定することで、
このラベル内の処理を延々と繰り返す、所謂無限ループ処理を書きます。
今回作成するOSに求める機能は「文字を表示すること」だけです。
なので、その役目が終わったらこの処理でOSちゃんにはゆっくり休んでいただきましょう。
##msgラベル
次はこの部分です。
msg:
DB 0x0a, 0x0a
DB "hello, world"
DB 0x0a
DB 0
やっと”hello, World"の文字が出てきましたね。
この部分を理解するには、putloopラベルの復習も必要になってきます。
まだ読んでない人はまず「2時限目:アセンブリ言語でソースコードを書こう②(putloopラベル)」をご参照ください。
ここから先は上記記事を読んでいただいた前提で進めていきます。
では、putloopラベルとmsgラべルの記述がどのように絡んでくるのか、
見ていきましょう。
putloopラベルはその名の通り、一定期間ループさせる部分です。
ではそのループを抜け出す条件は何か。そこが大事なのです。
MOV AL,[SI]
ADD SI,1
CMP AL,0
JE fin
上記コードは、putloopラベルの中から抜き出してきました。
ここで重要なのは次の点です。
1. ALにはSI([]が付いてるので指定メモリ番地の”内容”を格納する)が代入されていること
2.ALの値が0と等しくなった時、ループ処理を抜け出すこと
そして忘れちゃいけないのがこの一文
MOV SI,msg
つまり、これらを合わせて解釈すると、
「SIレジスタにはまずmsgラベルのメモリ番地を記憶させる。
SIに記憶させたメモリ番地からその番地に格納されているデータを呼び出し、ALレジスタにその内容を記憶させ、内容を表示する。
SIの値に+1をすることで、一つ先のメモリ番地の内容をALに記憶させ、内容を表示することができる。※これを繰り返す。
msgラベルの最後が0になっているのがミソで、SIに+1をし続けていくといつかこの0の値が入ったメモリ番地に行き着く。
そこで初めてCMP命令にて正となり、次のJE命令によってfinラベルに飛ぶことができる。」
となるわけです。
これで無事に文字を表示することができました。と言いたいところですが、
最後にあと2文あります。お付き合いください。
RESB 0x7dfe-$
DB 0x55, 0xaa
順に行きます。
まずRESB命令ですが、これは指定した番地まで0x00を自動挿入させる命令です。
OSにはセクタと呼ばれる区分みたいなものがあって、そのサイズは今回512と決まっています。
逆に言えば、512に満たないといけないのです。
そこで、もちろん0x00を512まで手入力していってもいいのですが、
それではあまりに人間業すぎるので、
この命令を使うわけです。
また今回は、命令の引数として「0x7dfe-$」と指定させていただきました。
これは「0x7dfeから現在のメモリ番地を引く」といった意味になります。
つまり、0x7dfeまでは何が何でも0x00を入力してくれるというわけです。
なんで0x7dfeまで0x00を入力したいのかは本日の最後にお伝えします。
次はDB命令です。
ここでは0x55,0xaaと指定していますが、これにも訳があります。
BIOSはOSを認識する際、ブートセクタの末尾2バイトの値が何なのかで、
読み込むべきものなのかそうでないのかを判断します。
なのでこれはブートセクタの末尾2バイト部分に記載しなきゃいけない決まり事だと理解してください。
さて、最後になんでさっき0x7dfeまで0x00を入力したかについてですが、
これはブートセクタのセクタ領域が0x7c00~0x7dffと決まっているからです。
このように決まっているので、単純に引き算して、0x7cdeまで0x00をいれるんですね。
いよいよ「なんちゃってOS(ブートセクタ編)」のソースコード分析は終了です。
あとは2日かけて、「アセンブル」と「実際に起動」をやっていきますよ♪
楽しみにしていてくださいね~♬
今日の授業終わり!