ブート

base version : v0.1.0

Raph KernelはGRUBから起動する事を前提として作られている。

GRUBは各種ハードウェア情報を集めてくれたり、最初から32bitプロテクトモードで起動してくれたりするため、ブートローダーを自力で書くのと比べてカーネル開発がかなりイージーモードになる。

ただし、ちゃんとGRUBが読めるようなフォーマットでカーネルバイナリを作りましょう、というのが今回のテーマ。

GRUBのインストール

GRUBマニュアル

ディスクイメージへのインストール:disk.sh#L34

config:grub.cfg

 

仕様書(multiboot specification 2)

仕様書

ヘッダーファイル

実装例:

boot.S

kernel.c

multiboot2.h

最小構成としてgrubのソースコード内の/grub-core/tests/boot/kernel-i386.Sが参考になる。

Raph Kernelはx64カーネルだが、grubはファイルシステムも解析できるし、elf64も解析できるので、multiboot specification2さえ押さえたelfバイナリを作ってディスクイメージに放り込めば、後は勝手にgrubがプロテクトモードでロードしてくれる。便利。

リンカスクリプト

リンカスクリプト(→kernel/kernel.ld)でバイナリ内でのデータの配置を決める。

大事なのは、multiboot headerを先頭に持ってくる事。(→kernel/kernel.ld#L11)先頭でなくても大丈夫なのだが、先頭が望ましい。ただし、先頭1MBはいろいろごちゃごちゃしているので、1MB以降の領域にする事。(→kernel/kernel.ld#L8)ついでにgrubからの起動直後のプロテクトモードで実行されるコードも固めて置いておく。

ちなみに、Raph Kernelはリンカスクリプトをカーネルのメモリ空間マップとして用いているので、他の項目を読んだ後にまた読み返してみると面白いかもしれない。

エントリポイント

リンカスクリプトで指定したエントリポイント(→kernel/kernel.ld#L3)がGRUBから呼び出される。くどいが、この時32bitプロテクトモードである。

エントリポイント(→boot/boot.S#L65)では、シグネチャの確認をした上で、レジスタの値を保存しておく。このレジスタの値は、GRUBが汗水垂らして集めてくれたハードウェア情報なので、後でC言語コード内から呼び出せるようにグローバル変数に格納する。ありがたや。

補足

リンカはgccやg++でなくてldにしなければならない。(→kernel/Makefile#L41

gccやg++を使うとセクションを配置する際にアライメントしようとするため、ファイル先頭からやたら離れた場所に配置しようとする。最小構成でmultiboot2ヘッダーをきちんと配置しているにも関わらず、「multiboot header not found」と言われてしまう場合は、ヘッダーがバイナリ上のどこにあるか確認すると良い。仕様によればファイル先頭から32768bytesまでの中にヘッダーが収まっている必要がある。

ブートとは関係ないのだが、メモ書き代わりに。

64bitコードをコンパイルする際、-mcmodel=large(→kernel/Makefile#L14)をつけずにリンカスクリプトの中の値を読もうとすると「再配置がオーバーフローしないように切り詰められました: R_X86_64_32」等と言われて怒られるので注意。

Q. なんでUEFIじゃないの?

A. UEFIが普及する前に書いてたカーネル(Raph Kernelとは別)では、grub起動が一番ラクだった。その時のコードを流用した結果、こうなっている。

UEFI実装をきちんとやっても良いのだけど、grubで十分起動できるのと、他にいろいろ実装しなきゃいけない事が多すぎてやってる暇がない。

あと、UEFIだとバイナリがPEだから、linux環境で簡単にコンパイルできないのも難点。

ちなみに、後方互換性を気にしているわけではない。UEFIが載ってない骨董品を相手にするのはメンドイ(多方面から刺されそうな発言)

広告

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中