ブート

僕が作っているOSはフロッピーから起動していました
フロッピーを使っているのは単純に簡単だからです
ブート方法も非常に簡単で、「30日でできるOS自作」という本に書いてあることを少しアレンジしただけのシンプルなものでした
したがってメモリ容量の取得方法も原始的な方法で行っています
今のところ別に問題があるわけではありませんが、なんとなくLinuxが利用しているGRUBに興味があり、GRUBをインストールしてみました
GRUBとは高機能なブートローダです
機能はOSのブートはもちろんのこと、リアルモードからプロテクトモードにしておいたりと大抵のOSがブート時に行うであろう共通の操作をやってくれます
まあ要するに細かい初期化を気にしないでOSを書くことができるわけです
僕はハードディスクのイメージを作成し、GRUBとOS本体をイメージにインストールする実験をしてみました

次のサイトを参考にしました(http://www.omninerd.com/articles/Installing_GRUB_on_a_Hard_Disk_Image_File
手順は次のようになります

  1. イメージファイルを作成する
  2. イメージにGRUBをインストールする

イメージファイル作成
まずイメージファイルになる空のファイルを作成します

$dd if=/dev/zero of=hdd.img bs=512 count=16065
ddコマンドはデバイスとファイルの入出力を行うコマンドです
/dev/zeroはゼロをひたすらに出力する仮想デバイスです
上記のコマンドでbs×count(8225280)バイトの空のファイルを作成することができます(16065は255(head)*63(cylinder)*1(sector)を表しています。この数値が適当だとパーティションを切る操作が少し複雑になるみたいです。ハードディスクはヘッド数が255でシリンダ数が63と設定する(?)参考 http://www.freebsd.org/doc/ja_JP.eucJP/articles/multi-os/x193.html

次にこのファイルをハードディスクデバイスとして扱うためにループデバイスにイメージを接続します

#losetup /dev/loop1 mnt/hdd.img

試しにfdiskで/dev/loop1を見てみましょう


# fdisk -ul /dev/loop1

ディスク /dev/loop1: 8 MB, 8225280 バイト
ヘッド 255, セクタ 63, シリンダ 1, 合計 16065 セクタ
Units = セクタ数 of 1 * 512 = 512 バイト
ディスク識別子: 0x00000000

ディスク /dev/loop1 は正常なパーティションテーブルを含んでいません

ちゃんとイメージが/dev/loop1接続されています(まだ何も操作していないのでパーティション情報が含まれていないですが)

さて次に/dev/loop1を介してイメージにパーティションを作成しましょう
パーティションについてよく知らなかったので次のサイトで勉強しましたhttp://nobumasa-web.hp.infoseek.co.jp/partition/partition.html
今回やることは簡単でディスク全体をLinux基本パーティションでカバーします

#fdisk /dev/loop1
デバイスは正常な DOS 領域テーブルも、Sun, SGI や OSF ディスクラベルも
含んでいません
新たに DOS ディスクラベルをディスク識別子 0xefdd4256 で作成します。
あなたが書き込みを決定するまで、変更はメモリ内だけに残します。
その後はもちろん以前の内容は修復不可能になります。
警告: 領域テーブル 4 の不正なフラグ 0x0000 は w(書き込み)によって
正常になります

コマンド (m でヘルプ): n
コマンドアクション
e 拡張
p 基本領域 (1-4)
p
領域番号 (1-4): 1
最初 シリンダ (1-1, 初期値 1): エンターキーで初期値を選択
初期値 1 を使います

コマンド (m でヘルプ): a
領域番号 (1-4): 1

コマンド (m でヘルプ): w
パーティションテーブルは変更されました!

ioctl() を呼び出してパーティションテーブルを再読込みします。

警告: パーティションテーブルの再読込みがエラー 22 で失敗しました: 無効な引数です。
カーネルはまだ古いテーブルを使っています。新しいテーブルは
次回リブート時か、partprobe(8)またはkpartx(8)を実行した後に
使えるようになるでしょう
ディスクを同期しています。

基本パーティションを作成し、ブート可能な印をつけます。最後に書き込むのを忘れないように(僕は忘れてました)

先ほど同様に確認してみます


# fdisk -ul /dev/loop1

ディスク /dev/loop1: 8 MB, 8225280 バイト
ヘッド 255, セクタ 63, シリンダ 1, 合計 16065 セクタ
Units = セクタ数 of 1 * 512 = 512 バイト
ディスク識別子: 0xefdd4256

デバイス ブート 始点 終点 ブロック Id システム
/dev/loop1p1 * 63 16064 8001 83 Linux

先ほどと異なりパーティションが作成されています

基本パーティションが作成されたので、パーティション上にファイルシステムを作成します(GRUBをインストールするためには特定のファイルシステムが必要です(多分))
現在はloop1デバイスはハードディスクイメージ全体を指しているのでこのままではパーティションを操作できません
そこでloop2デバイスに作成したパーティションを接続します


#losetup -o 32256 /dev/loop2 /dev/loop1
32256は63×512(sector*byte)です。作成したパーティションはディスクの63セクターからディスクの最後まで占めており、-oオプションで先頭を指定することでループデバイスパーティションを接続できます

そしてファイルシステムパーティション上に作成します


mkfs /dev/loop2

これでイメージファイルの作成は終了です

GRUBインストール
次にイメージにGRUBをインストールします
まず先ほどから操作しているパーティションをmnt以下のファイルにマウントします

# mkdir mnt/hdd
# mount /dev/loop2 mnt/hdd
もちろんmnt/hddの中身は空っぽです

つぎにLinuxGRUBが使用しているファイルを流用するためにそれらをコピーします
またGRUBから起動されるカーネル(the_kernel)もコピーしておきます。(GRUBから起動されるカーネルは一定の仕様を満たしている必要がありますhttp://www.gnu.org/software/grub/manual/multiboot/multiboot.html
僕はhttp://d.hatena.ne.jp/wocota/searchdiary?word=GRUBOSのようなものさん)を参考にしました


#mkdir -p mnt/hdd/boot/grub
#cp -r /boot/grub/stage1 /boot/grub/stage2 /boot/grub/menu.lst /boot/grub/grub.conf mnt/hdd/boot/grub 
#cp -r the_kernel mnt/hdd/
参考にしたページWelcome to OmniNerd.com – Amazing Content From Around The Web For Discerning Nerdsには書いてなかったのですが、僕の環境では/boot/grub/menu.listは/boot/grub/grub.confへのリンクでした
なので両方コピーしておきます

さて準備が整いました。GRUBをインストールし、the_kernelをロードするように設定しましょう
まずGRUBをインストールします


#grub --device-map=/dev/null


GNU GRUB version 0.97 (640K lower / 3072K upper memory)

[ Minimal BASH-like line editing is supported. For the first word, TAB
lists possible command completions. Anywhere else TAB lists the possible
completions of a device/filename.]
grub> device (hd0) hdd.img
device (hd0) hdd.img
grub> root (hd0,0)
root (hd0,0)

Filesystem type is ext2fs, partition type 0x83
grub> setup (hd0)
setup (hd0)
Checking if "/boot/grub/stage1" exists... yes
Checking if "/boot/grub/stage2" exists... yes
Checking if "/boot/grub/e2fs_stage1_5" exists... no
Running "install /boot/grub/stage1 (hd0) /boot/grub/stage2 p /boot/grub/grub.conf "... succeeded
Done.

the_kernelをブートするようにmnt/hdd/boot/grub/menu.lstを編集します


#mnt/hdd/boot/grub/menu.lst(->mnt/hdd/boot/grub/grub.conf)
default=0
timeout=0
hiddenmenu
title myOSname
root (hd0,0)
kernel /the_kernel

これで実行する準備が整いました
実行してみましょう


$qemu -hda hdd.img

以上です
誤り等がありましたらご指摘お願い致しますm(__)m