ブートローダーを作る(1)
こんにちは。
タイトルの通りブートローダーを作ります。
※長ったらしくて拙い文章です。
ブートローダーはOSを起動するのに必須のプログラムです。この仕組みを理解することでコンピューターやOSの仕組みを理解することができます。
大まかな流れとしては、アセンブリコードを書いてアセンブルしてできたバイナリファイルを仮想マシン(QEMUというのを使います)上で起動させます。
準備
まずはQEMUをインストールします。MacでQEMUをインストールするにはHomebrewというものが必要になりますので、まずHomebrewをインストールします。
そして更にHomebrewをインストールするためにCommand Line Tools for Xcodeをインストールします・・・・めんどくさい・・・
いよいよコマンドの入力です。ターミナルを起動して以下のコマンドを入力してください。
$ xcode-select --install
このコマンドを入力して出てきたナビゲーターに沿ってインストールをしてください(とりあえず何も考えず次に進めれば大丈夫です)
インストールが終わったらHomebrewの公式サイト
Homebrew — The missing package manager for OS X
へアクセスして一番下のInstall Homebrewのところにあるコマンドをターミナルで実行してください。
$ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
この後
$ brew doctor
を実行することが推奨されていて、実行すると警告が出るのですが特に差し障りなかったので自分は何も修正していません笑
いよいよQEMUをインストールする準備が整いました。以下のコマンドを入力してください。
$ brew qemu
これでインストールは完了です。以下のコマンドが通ったらインストールは成功です。
$ qemu-system-i386 -version
↓自分の環境での実行結果
これで準備は整いました。
ブートローダーの枠組み
何もしないブートローダーの枠組みを作ります。
まずは以下のコードを入力してboot.Sという名前で任意の場所に保存してください。
[bits 16] [org 0x7C00] cli hlt times 510-($-$$) db 0 dw 0xAA55
ターミナルを開き、コードが保存してある場所にcdしnasmでアセンブルします。
$ nasm -f bin -o boot.bin boot.S
では以下のコマンドを入力してQEMUで動かします。FDからの起動とします。
$ qemu-system-i386 -fda boot.bin
以下のようになれば成功です。
コードの説明
1、2行目はnasmに対する命令です。
1行目
[bits 16]
16ビットでアセンブルするための宣言です。
CPUは起動した最初は16ビットモードで動きます。このモードをリアルモードといいます。
リアルモード
リアルモードは16ビットレジスタしか使えないのでアクセスできるメモリの領域幅は最初に指定したメモリ番地(ここでは0x7C00)を基点にして0x7C00+0x0000〜0x7C00+0xFFFFという狭い範囲になります。
ここではあまり意識しなくていいです。
現在の全てのBIOS、windows95以前の全てのOSはリアルモードで動作していました。
2行目
[org 0x7C00]
MBR(後述)をメモリの0x7C00から読み込む宣言です。
ブートローダーはMBRの中に入っています。
MBR(Master Boot Record)は起動可能なデバイスの先頭512バイトに保存されています。MBRの中にあるプログラムをブートローダーといいます。
MBRの中身
0~445 ブートローダー
446~494 パーティションテーブル
510 55(ブートシグネチャ)
511 AA(ブートシグネチャ)
このように、ブートローダーには446バイトのサイズ制限があります。ですので基本的にはこの部分からOSのプログラムを呼び出す形になります。
パーティションテーブルには各パーティションの位置情報、種類、起動フラグが起動されています。
510バイト目と511バイト目はブートシグネチャといってこのプログラムがMBRである事を示すための数字です。これがないとMBRは無効とされブートローダーはスルーされます。
この2バイトをリトルエンディアンで0xAA55と表します(順番が逆)
0xAA55はマジックナンバーで、特に意味のない数字です。最初にOSを開発していた人たちがテストで入れていた値の名残みたいです。
3、4行目
cli hlt
この2つはアセンブリの命令です。
cli命令はBIOSによる割り込みフラグをリセットする命令です。
念のため、書いておきます。
hlt命令はCPUの動作を止める命令です。この命令が実行されるとプログラムが終了します。ここでの例は本当に何もしないプログラムです。
5、6行目
times 510-($-$$) db 0 dw 0xAA55
この2行でMBRのブートシグネチャを書き込みます。timesとdbは疑似命令といい、機械語と1対1で対応しておらず、アセンブラにより機械語へ翻訳されます。
まず$と$$の説明です。$$はこのプログラムの一番最初の命令を指します。$は現在の命令を指します。
そして、times疑似命令は指定された回数分処理を繰り返す動作をします。
db疑似命令はdata byteのことで、そのメモリの場所にデータを置く動作をします。
ですのでこの5行目のコードは現在のメモリアドレスから510バイト目まで0で埋めます。
そして6行目のdw擬似命令(data double byte)で511バイト目と512バイト目に55とAAを置きます。これが前述のブートシグネチャです。
今回は本当に何もしないブートローダーの枠組みと理解するための基礎について書きました。自分は以下の本を参考にしました。
作りながら学ぶOSカーネル―保護モードプログラミングの基本と実践
- 作者: 金凡峻
- 出版社/メーカー: 秀和システム
- 発売日: 2009/04
- メディア: 単行本
- 購入: 7人 クリック: 89回
- この商品を含むブログ (14件) を見る
余談
あと、このブートローダーの枠組みですが、アドレスの指定方法がいくつかあります。OSDev.orgこんな記事がありました。
OSDev.org • View topic - [ORG 0x7C00] vs mov ax, 0x07C0 vs jmp 0x07C0:start
なかなか面白いです。この記事などもなかなか参考になります。
Real mode assembly I - OSDev Wiki
日本語サイトでも
Linuxをはじめよう!:1から創る自作OS 0x00+
0から作るOS開発
この2サイトにはかなりお世話になっています。この方々にいつか追いつける事を夢見てます・・・
AT&T記法しかわからない自分にとってIntel記法のいい勉強になってます。。。
AT&T記法でも書けるようになりたいです。