30日でできるOS自作入門_DAY1 & DAY2

DAY1

  • バイナリファイル自体は2進数だが、それでは冗長になるので、 以下のように2進数⇒16進数に変換することで情報量を減らしている

f:id:smatsuzaki:20191130120403p:plain

  • DB命令 : data byte命令、ファイルの内容を1byteだけ直接書く。文字列も書けるよ!
  • PRESS命令 : reserve byte 、引数 x byteを予約する、具体的には0x00を書きこんで埋める
  • DW命令 : data word、DB命令の仲間 word=16bit/2byte
  • DD命令 : data double word、DB命令の仲間 word=32bit/4bit

DAY2

その後、フロッピーからBIOS的なものを起動するアセンブラなコードを写経する。 以下、処置の流れのメモ。

ORG命令で、0x7c00(16進数7C00 = 10進31744)を読み込まれるアドレス番地として指定

ORG     0x7c00          ; プログラムが読み込まれるメモリアドレスを指定

その次に出てくるのは、JMP命令。entryラベルにgo toする。

JMP     entry

entryに入り、MOV AX,0で AX = 0; として処理される。0を値として入れることは初期化と呼ばれている。

entry:
        MOV     AX,0            ; レジスタ初期化
        MOV     SS,AX
        MOV     SP,0x7c00
        MOV     DS,AX
        MOV     ES,AX

        MOV     SI,msg

上記のentryラベルの区画の最後の「MOV SI,msg」においてSIに代入される「msg:」はラベルである。 アセンブラでラベルが代入されるときはラベルが格納されているメモリ番地が格納される。

putloop:
        MOV     AL,[SI]
        ADD     SI,1            ; SIに1を足す
        CMP     AL,0
        JE      fin
        MOV     AH,0x0e         ; 一文字表示ファンクション
        MOV     BX,15           ; カラーコード
        INT     0x10            ; ビデオBIOS呼び出し
        JMP     putloop

次のputloopラベルに移る。

最初の「MOV AL,[SI]」の「 [SI] 」はSIレジスタではなく、メモリ番地を指し示す。 例えばSIレジスタに987が値として格納されていれば、「987番地のメモリに格納された値を1byte取り出しALレジスタに代入(格納する)」となる 特に明示的に書かれていないが、

  • MOV AL,[SI] 1ビット取り出し
  • MOV BYTE AL,[SI] 8ビット取り出し
  • MOV WORD AL,[SI] 16ビット取り出し
  • MOV DWORD AL,[SI] 32ビット取り出し

となるらしい。

メモリの1区画の大きさについては、

メモリは基本、8bit(0か1を8個並べたもの)ごとに1区画として、1区画ごとにアドレス(番地)が振られている。

ざっくりアセンブラ入門

とのこと。

ADD        SI,1            ; SIに1を足す

その次のADD命令は足し算となる。 ADD SI,1 は SI = SI + 1;

CMP     AL,0
        JE      fin

ここは1セットの構文で、CMPが if ( AL == 0)

JEが then go to fin というような動きとなる。

JE は「jump if equal」の略称

INT        0x10            ; ビデオBIOS呼び出し

INT命令はinterrupt(ハードウェア割り込み?)を発行している?

以下を全て実行すると、BIOS経由で画面に文字が出力できるとのこと

一文字表示
AH = 0x0e
AL = キャラクターコード
BH = 0
BL = カラーコード
戻り値:なし

話を戻し、「 CMP AL,0 CMP AL,0 JE fin」からfinラベルに飛び

fin:
        HLT                     ; 何かあるまでCPUを停止させる
        JMP     fin             ; 無限ループ

HLT命令を実行すると、PC(サーバ)はハードウェア割り込みが検知される(キーボードを押すとか)までの 間スリープに入る模様。

最後に冒頭のORG命令で0x00007c00が指定された意味が語られているが以下の記事が理解できればOKだと思う。

https://ja.wikipedia.org/wiki/%E3%83%96%E3%83%BC%E3%83%88%E3%82%BB%E3%82%AF%E3%82%BF

要するにBIOSの仕様として、「OSは0x7c00にブートすること!」という決まりがあるとの理解でだいたい間違ってなさそう。

より詳しくは、ここのサイトを読むといいかも。

MBRの実行手順だけ、覚えておきたいのでメモ

  1. BIOSがPOST(Power On Self Test)を実行
  2. POST後、BIOSFDD or HDDのMBR0x7C00にロードし、そこから処理を続行する。(もちろんCD/DVDからブートすることも出来るが、本記事ではFDD/HDDからのブートを扱う。)
  3. MBRにはOSのカーネルをロードし、実行する為の機械語が格納されており、OSのブートが始まる。

その後はMakefileの話題。

# デフォルト動作

default :
    ../z_tools/make.exe img

# ファイル生成規則
# ipl.nasとMakefileが存在することを確認後、ipl.nasを元にipl.binとipl.lastを生成する
# ipl.binとMakefileが存在することを確認後、

ipl.bin : ipl.nas Makefile
    ../z_tools/nask.exe ipl.nas ipl.bin ipl.lst

helloos.img : ipl.bin Makefile
    ../z_tools/edimg.exe   imgin:../z_tools/fdimg0at.tek \
        wbinimg src:ipl.bin len:512 from:0 to:0   imgout:helloos.img

# コマンド

asm :
    ../z_tools/make.exe -r ipl.bin

img :
    ../z_tools/make.exe -r helloos.img

run :
    ../z_tools/make.exe img
    copy helloos.img ..\z_tools\qemu\fdimage0.bin
    ../z_tools/make.exe -C ../z_tools/qemu

install :
    ../z_tools/make.exe img
    ../z_tools/imgtol.com w a: helloos.img

clean :
    -del ipl.bin
    -del ipl.lst

src_only :
    ../z_tools/make.exe clean
    -del helloos.img

今まで作っていたバッチファイルが全てMakefileに統合された。素晴らしい!

cleanとかrc_onlyの書き方も参考になる。

/* https://sunrise033.com/entry/hatena-blog-how-to-hierarchicalize-categories */