Linuxで書くOS自作入門 2日目
「30日でできる!OS自作入門」の2日目
環境はUbuntu, アセンブラはNASMで開発中
アセンブリの更新
- プログラム本体部分が意味を持つ命令で置き換えられた.
- ラベルが追加された.
- レジスタ名が記述されるようになった.
- 新しいアセンブリ命令
- 今まで空き部分を0で埋めるために使用していたRESB命令は警告が出るので,TIMES命令によって置き換えることにした.
TIMES
指定回数直後の命令を繰り返す
例RESB 18
→TIMES 18 DB 0
Makefileの作成
Win版のMakefileをもとに,Linuxで動作するように書き換えた.本では,独自ツールedimg.exeなどが登場するが,これらに頼らず自分でディスクイメージを作成する.今日の範囲ではブートセクタの部分とそれ以外の部分をcatで結合しているだけである.
ここでは,ファイル名を変更し,ブートセクタのアセンブリをipl.asm
,それ以外のアセンブリをtail.asm
としている.
default : make img ipl.bin : ipl.asm Makefile nasm ipl.asm -o ipl.bin -l ipl.lst tail.bin : tail.asm Makefile nasm tail.asm -o tail.bin -l tail.lst helloos.img : ipl.bin tail.bin Makefile cat ipl.bin tail.bin > helloos.img asm : make -r ipl.bin img : make -r helloos.img run : make img qemu-system-i386 helloos.img clean : -rm ipl.bin -rm tail.bin -rm ipl.lst -rm tail.lst src_only : make clean rm helloos.img
ブートセクタの簡単な解釈
ブートセクタ部分に関してはアセンブリが読めるようになってきたため,ここでアセンブリが何をしているのか読んで見る.その前に用語を整理する.
- ブートセクタ ディスクの最初のセクタ.そもそもセクタはディスクの読み書きの最小単位であり,512バイトである.最初にここを読み込むことによって,OSは起動する.
- FAT12フォーマット フロッピーディスクのフォーマット形式
ORG 0x7c00
機械語翻訳はされない,アセンブラのための命令.ブートセクタは0x00007c00 - 0x00007dffに読み込まれるので,これを明示化している1.絶対アドレスを正しく計算するために使っているのだと思う.
JMP entry DB 0x90 DB "HELLOIPL" ; ブートセクタの名前を自由に書いてよい(8バイト) DW 512 ; 1セクタの大きさ(512にしなければいけない) DB 1 ; クラスタの大きさ(1セクタにしなければいけない) DW 1 ; FATがどこから始まるか(普通は1セクタ目からにする) DB 2 ; FATの個数(2にしなければいけない) DW 224 ; ルートディレクトリ領域の大きさ(普通は224エントリにする) DW 2880 ; このドライブの大きさ(2880セクタにしなければいけない) DB 0xf0 ; メディアのタイプ(0xf0にしなければいけない) DW 9 ; FAT領域の長さ(9セクタにしなければいけない) DW 18 ; 1トラックにいくつのセクタがあるか(18にしなければいけない) DW 2 ; ヘッドの数(2にしなければいけない) DD 0 ; パーティションを使ってないのでここは必ず0 DD 2880 ; このドライブ大きさをもう一度書く DB 0,0,0x29 ; よくわからないけどこの値にしておくといいらしい DD 0xffffffff ; たぶんボリュームシリアル番号 DB "HELLO-OS " ; ディスクの名前(11バイト) DB "FAT12 " ; フォーマットの名前(8バイト) TIMES 18 DB 0 ; とりあえず18バイトあけておく
FAT12フォーマットフロッピーディスクのための記述であり,BPB(BIOS Parameter Block)と呼ばれるらしい.FATボリュームの認識のための記述.明確に定められた部分が多い.
ここに詳しく書いてあった.ELM FATファイル システムのしくみと操作法
entry: MOV AX,0 ; レジスタ初期化 MOV SS,AX MOV SP,0x7c00 MOV DS,AX MOV ES,AX MOV SI,msg
最初の命令,JMP entry
によってジャンプして最初に実行されるこのプログラムをブートストラッププログラムと呼ぶ.最初はレジスタの初期化が行われている.特筆すべきはスタックポインタSPはブートセクタの開始位置0x7c00に,ソースインデックス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
ソースインデックスSIの指すアドレス部分をALに読み込み,0x0eをAHに読み込んだ後,INT 0x10
命令を使うことによって文字が表示される.文字列が終わるってALがゼロになるまでループしている.
ここに詳しく書いてあった.(AT)BIOS - os-wiki
fin: HLT ; 何かあるまでCPUを停止させる JMP fin ; 無限ループ
HLT
は次の外部割り込みが発生するまでCPUを停止させる命令でこれを無限ループしている.これ無しで実行するとCPUが動き続けるらしく,ファンがうるさくなった.
msg: DB 0x0a, 0x0a ; 改行を2つ DB "Hello, world! " DB 0x0a ; 改行 DB 0
メッセージ部分.好きな文字を書ける.
TIMES 0x7dfe-0x7c00-($-$$) DB 0 ; 0x7dfeまでを0x00で埋める命令
ブートセクタの最後0x7dffから最後の2バイトを除いた0x7dfeまでを0で埋める.
DB 0x55, 0xaa
最後の2バイトをこれにすることによって,有効なブートセクタであることを示す.