GRUBを使い、ブートのコードを書かずにカーネルを起動させる。

カーネルの開発に必要なもの

1. 仮想マシンGRUBを使っているOSを入れる

自分の場合は、ubuntu-jaを使っているので、仮想マシンにもubuntu-jaをいれた。

ubuntuのディスクイメージはhttp://www.ubuntulinux.jp/downloadからダウンロードできる。

vmplayerのディスクイメージの作成と、起動は次のようにすればいい。

qemu-img create -f vmdk ubuntu.vmdk 10G
vmplayer ubuntu.vmx

ubuntu.vmx

ubuntu.vmxの設定ファイルはネットに色々のっているのでコピー&ペーストで作成した。

config.version = "8"
ide0:0.present = "true"
ide0:0.fileName = "ubuntu.vmdk"
ide1:0.present = "true"
# CD-ROMを利用はこっちのコメントを外す
#ide1:0.fileName = "auto detect"
#ide1:0.deviceType = "atapi-cdrom"
# ISOイメージを利用する場合
ide1:0.fileName = "./ubuntu-ja-6.06-desktop-i386-20060805.iso"
ide1:0.deviceType = "cdrom-image"

floppy0.startConnected = "FALSE"
floppy0.present = "TRUE"
floppy0.fileName = "/dev/fd0"
floppy0.deviceType = "file" # floppy-image

ethernet0.present = "true"
ethernet0.connectionType = "nat"
guestOS = "otherlinux"

displayName = "ubuntu-ja-6.06-desktop-i386-20060805"
memsize = "256"

ide0:0.redo = ""
ethernet0.addressType = "generated"
uuid.location = "56 4d 88 72 1c 10 4d 84-57 2a ed 07 a8 ff 36 d4"
uuid.bios = "56 4d 88 72 1c 10 4d 84-57 2a ed 07 a8 ff 36 d4"
usb.present = "TRUE"
ethernet0.generatedAddress = "00:0c:29:ff:36:d4"
ethernet0.generatedAddressOffset = "0"
checkpoint.vmState = ""

tools.remindInstall = "TRUE"

2. GRUBのコードを手に入れる。

下のサイトに詳しい情報が書いてある。

http://www.gnu.org/software/grub/grub-legacy-download.en.html

簡単にコードを手に入れたいなら、次のようにする。

cvs -z3 -d:pserver:anonymous@cvs.savannah.gnu.org:/sources/grub co grub

3. カーネル開発に必要なファイルをコピーする

適当なディレクトリを作成し、必要なファイルをコピーする。

mkdir example-kernel
cp ./grub/docs/boot.S ./example-kernel
cp ./grub/docs/kernel.c ./example-kernel
cp ./grub/docs/multiboot.h ./example-kernel

4. コンパイル、インストール

コンパイル

コンパイルにはすこし注意が必要

ここは、あまりよく理解していないので書いてあることを当てにしない方がいい。

  • カーネルは/usr/include をインクルードをできない。
  • カーネルは標準ライブラリ(libc, glibcなど)を含めることができない。
  • カーネルがスタートする場所は、0x100000(1Mbyte)からにするとうまくいく。
    • GRUBが0x10000 からメモリにカーネルをロードするからだと思われる。
GCC マニュアル抜粋
-nostdinc
ヘッダファイルのための標準のシステムディレクトリを検索しません。‘-I’オプションによって指定したディレクトリ (またはカレントディレクトリ) のみを検索します。‘-nostdinc’ と ‘-I-’を使用することにより、インクルードファイルの検索パスを明示的に指定したディレクトリのみに限定することが可能となります。
-nostdlib
リンク時に、標準のシステムライブラリとスタートアップファイルを使用しません。指定したファイルのみがリンカに渡されます。
-fno-buitin
ビルトイン関数のうち、2つのアンダースコアで始まるもの以外を認識しなくなります。現在、この指定は_exit, abort, abs, alloca, cos, exit, fabs, labs, memcmp, memcpy, sin, sqrt, strcmp, strcpy, strlen の関数に影響を及ぼします。
-ffreestanding
フリースタンディング実行環境 (freestanding environment) 用にコンパイルを行います。これにより、‘-fno-builtin’ オプションが有効になり、また、 main に特別な条件は不要とみなします。
LD マニュアル抜粋
-Ttext org
それぞれ出力ファイルの bss、data、text セグメントに対して org を開始アドレスにする。org は16進の整数でなければならない。
-e entry
entryをプログラムのエントリポイントを示すシンボルとして取り扱う (デフォルトのエントリポイントを上書きする)。デフォルトと他のエントリポイントの指定方法については ld の info の *Note Entry Point:: を参照すること。
cd example-kernel
gcc -c -ffreestanding -nostdinc -nostdlib -I. boot.S    
gcc -c -ffreestanding -nostdinc -nostdlib -I. kernel.c
ld -Ttext 0x100000 -e start -o kernel kernel.o boot.o
インストール

できればフロッピーを使わずにフロッピーのイメージを作り、そのイメージにカーネルを書き込めればよかったけど、やりかたがよくわからなかった。

フロッピーディスクを入れ、次のようにする。

fdformat /dev/fd0                       # フォーマット
mkfs -t ext2 /dev/fd0                   # ext2ファイルシステムを作成
mkdir /mnt/floppy                       # マウントする場所を作成
sudo mount -t ext2 /dev/fd0 /mnt/floppy # フロッピーをマウント
cp kernel /mnt/floppy/                  # インストール
sudo umount /mnt/floppy                 # アンマウント

5. GRUBのメニューの編集

GRUBのメニューを編集することによって、ブート時にロードするカーネルを選ぶことができる。

仮想マシンを起動し、カーネルが起動できるようにGRUBを編集する。

/boot/grub/menu.lst に次のコードを追加する。

title Sample Kernel
root (fd0)
kernel /kernel
savedefault
boot

他の、savedefaultをコメントにする。

6. 起動

起動にはちょっと知らないといけいなことがある。

ubuntu.vmx のフロッピーの部分を見てほしい。

floppy0.startConnected = "FALSE"
floppy0.present = "TRUE"
floppy0.fileName = "/dev/fd0"
floppy0.deviceType = "file" # floppy-image

最初フロッピーを入れながら起動すると、ブートディスクと勘違いされるので、フロッピーを利用不可にする(フロッピーのツールバーが×になっているはず)。

GRUBを立ち上がったら、vmplayerのフロッピーのツールバーをオンにする。

そして、起動するカーネルを選べばカーネルが立ち上がる。

スクリーンショット

うまくいけば、次のような画面が表示される。