Linuxカーネルのテスト実行とデバッグ (1) :QEMU編

Linuxカーネルに新機能を追加したり、デバッグなどの変更をしたら、動作を確認するテストを実行するわけですが、実機で実行しようとするといろいろ面倒です。そこでQEMUの登場です。QEMUはシステムエミュレータの1つで、x86 PCをはじめARM, SPARC, MIPS, PPCなど、いろいろなプロセッサアーキテクチャをサポートした非常に高機能なエミュレータです。また、KVMでデバイスをエミュレーションする用途でも使われています。

QEMUをカーネルの開発に使うことには以下のメリットがあります。

  • 開発用PCをいちいちリブートしたり、またはもう1台テスト用のPCを用意したりする必要が無い。
  • ビルドしたカーネルをすぐに実行できるため、変更・ビルド・テストのサイクルを高速にまわせる。
  • デバッグメッセージやパニック時のメッセージをターミナルで見れ、必要ならばファイルに保存できる。

手間がかからずに、ビルドしたカーネルを試せるのは、非常に便利です。

今回は、QEMUでLinuxカーネルを実行する環境を構築するところまでを見ていきたいと思います。

QEMUの用意

http://www.qemu.org/download/ からバイナリまたはソースコードダウンロードするか、https://github.com/qemu/qemu からcloneします。ソースコードをダウンロード (またはgit clone) した場合はコンパイルする必要がありますが、自分の用途に合わせて configure 可能です。

x86_64のLinuxカーネルだけ実行できれば十分という場合は、例えば以下のように configure を実行します。

softmmuというのが、カーネルを実行可能なプロセッサエミュレータを指定するオプションになります。コンパイルするために必要なライブラリが足りないと configure がエラーになりますので、足りないものを追加するか、必要ないと思ったらエラーを出したオプションをdisableします。上記の例では、コンソールをVNCで表示可能にするオプションはenableするけど、saslでの認証はdisableしています。

configure できたら make するだけです。

コンパイルが終了したら x86_64-softmmu/qemu-system-x86_64 が出来ています。

Linuxカーネルのコンフィグとビルド

当然ですが、LinuxカーネルをQEMUがサポートするデバイスに合わせて、また必要ないデバイスや機能は外してコンフィグすれば、コンパイルする必要のあるファイルが減りますので、ビルドの時間も短くなります。QEMU がサポートするデバイスはドキュメンテーション http://www.qemu.org/documentation/ に書かれています。また、QEMUでお手軽にLinuxカーネルを実行するには、ローダブルモジュールは使わず、vmlinuxに全部リンクしてしまいましょう。

QEMU上でのLinuxカーネルの実行

Linuxカーネルがビルドできたら早速実行してみましょう。

オプションは -m の後にはメモリサイズ (MB)、-kernel の後にカーネル (bzImage) を指定します。今回は、ターミナルにカーネルからのメッセージが表示されるようにシリアルコンソールを使用します。そのために、QEMUのオプションして -nographic を指定し、Linuxカーネルの方には console=ttyS0 が渡されるように -append の後に付けておきます。

ブートに失敗しました。QEMUを終了するには Ctrl-A x を押します。ちなみに、Ctrl-A h と押すとヘルプが表示され、Ctrl-A c と押すと QEMU monitor に入ります。QEMU monitor では、レジスタダンプやメモリダンプ、その他プロセッサの情報を取得することができます。

ブートメッセージには  Unable to mount root fsと表示されています。ストレージデバイスを指定していませんので、ルートファイルシステムがないわけですね。

Initrdの作成

initrd (initramfs) は、Linuxカーネルが起動直後にメモリ上に読み込み(その名の通り)ラムディスクに展開するファイルシステムのイメージです。ブートローダが、カーネルと一緒に読み込みメモリ上に展開するので、カーネルが起動直後に使用可能になります。様々なストレージのためのデバイスドライバやファイルシステムを全てカーネルに組み込むとカーネルが巨大化してしまいますので、ターゲットシステムのルートファイルシステムをマウントするために必要となるドライバ類はinitrdが提供するようにすると、カーネル自体は必要最小限に抑えることができるようになります。

通常は、本来のストレージ上のルートファイルシステムをマウントした段階で、initrdが提供した仮のルートファイルシステムは不要になります。しかしながら、テスト用のプログラムを入れておき、実行することもできますので、ここではその目的のために使用します。

initrdのイメージは、その内容としたいディレクトリ構造をcpioでアーカイブし、gzipにより圧縮したものです。そこで、initrdを作成するためには、まず適当なディレクトリを作成し、initrdの内容とするファイルを集めます。例えば、シェルとしてbusyboxを使用することにすると、そのディレクトリをインストール先にします。以下は、そのようにして作成したものになります。

libはlib64へのシンボリックリンクです。initがinitrdの内容をマウント直後に実行するプログラムとなります。例えば以下の内容にします。

/sbin/init は busybox へのシンボリックリンクです。mount -a で /dev, /proc, /sys をマウントできるように、以下のetc/fstabも用意しておきます。

このディレクトリで以下のコマンドを実行するとinitrd.imgというファイル名でinitrdを作成できます。

QEMUにinitrdのファイルイメージを読み込ませるには -initrd オプションでinitrdファイルを指定します。

これでカーネルをブートすると、以下のようにカーネルがブート後にinitrdがマウントされシェルが使える状態になります。

/etc/init.d/rcSがないと怒られていますが、initの内容を移せば表示されなくなります。

おわりに

今回は、Linuxカーネルのテスト実行を行うために、QEMUを用いる方法を紹介しました。ルートファイルシステムをinitrdとすることで、気軽にカーネルをブート、テスト実行、終了することができます。次回は、QEMUにGDBを接続してみましょう。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です