2010年02月01日
QEMUで動作したDebianのカーネルをリビルドする
基本方針
Debianのソースパッケージをapt-getで取得して、それをそのままビルドすればよいわけですが、qemu上でのコンパイルはとてもとても時間がかかります。一晩かけても終わりません。
なので、qemu上のarmのDebianではソースパッケージの取得とそのソースの展開とパッチの適用まで行い、そのソースをPCのLinuxに持ってきて、そこでクロスコンパイルするようにします。
最初は /boot/config-2.6.26-2-versatile のとおりにビルドして動作を確認し、次にconfigを変更してカスタマイズしていきます。
以下、armel$のプロンプトはqemu上のarmのDebian, 単なる$はPCのLinux での操作であることを示します。
カーネルのソースパッケージの取得
armel$ su # apt-get build-dep linux-image-2.6.26-2-versatile # exit armel$ mkdir work armel$ cd work armel$ apt-get source linux-image-2.6.26-2-versatile
ソースの展開とパッチの適用
armel$ cd linux-2.6-2.6.26/ armel$ debian/rules source 2>&1 |tee source.log
debian/rules build
と実行すれば一気にビルドまでやってくれますが、ソースを展開してパッチを適用したところで止めるためには debian/rules source とします。何をやったか後で調べられるように tee コマンドでログをファイルに落としておきます。
これが完了すると、debian/build/source_armel_none のディレクトリにパッチを適用されたカーネルのソースが展開されるので、これをまるごとPCのLinuxに転送します。
(最初からworkのディレクトリをPC LinuxにNFSでマウントしておくと楽です。それに関してはこのページ)
カーネルのビルド
ビルドはPCのLinuxで行います。
configファイルは arm Debianの /boot ディレクトリからあらかじめコピーしておいてください。
クロスコンパイラはandroidのソースツリーにあったものを流用しました。$ANDROID はandroidのソースツリーの先頭です。
$ cd source_armel_none/ $ cp $HOME/config-2.6.26-2-versatile . $ export ARCH=arm $ export CROSS_COMPILE=$ANDROID/prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin/arm-eabi-
カーネルのロードモジュールを配置するディレクトリ名はカーネルのバージョンと関連付けられているので、MakefileのEXTRAVERSIONの値を以下のように修正します。
$ diff -u Makefile.org Makefile --- Makefile.org 2010-01-29 16:53:46.000000000 +0900 +++ Makefile 2010-01-29 16:54:13.000000000 +0900 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 26 -EXTRAVERSION = +EXTRAVERSION = -2-versatile NAME = Rotary Wombat
これでビルドします。最初はconfigを変更せずに試してください。
$ cp config-2.6.26-2-versatile .config $ make menuconfig $ make zImage 2>&1 |tee make.log
arch/arm/boot/zImage に起動に使う圧縮されたカーネルイメージができあがります。vmlinuz-2.6.26-2-versatile の代わりにこれを使ってqemuを起動し、問題なく立ち上がることを確認します。
$ qemu-system-arm -M versatilepb \ -kernel zImage \ -initrd initrd.img-2.6.26-2-versatile \ -hda hda.img.qcow2 \ -append "root=/dev/sda1"
ブート時に使用するカーネルモジュールをカーネルに最初から組み込むことにしてinitrdを不要にする
組み込みシステムでは起動するときに使用するデバイスは変わることがありません。なので必要なカーネルモジュールはカーネルに組み込んでしまったほうがシンプルになります。それによってinitrdが不要になり起動シーケンスも簡略化できます。
arm Debianが起動した後に、使用されているカーネルモジュールを知るには以下のコマンドを使います。
armel$ lsmod Module Size Used by ipv6 287700 10 loop 14124 0 smc91x 15140 0 psmouse 38192 0 sg 31568 0 sr_mod 15908 0 cdrom 35928 1 sr_mod ext3 122728 1 jbd 45332 1 ext3 mbcache 7936 1 ext3 sd_mod 25232 3 sym53c8xx 67188 2 scsi_transport_spi 24224 1 sym53c8xx scsi_mod 150212 5 sg,sr_mod,sd_mod,sym53c8xx,scsi_transport_spi
これらのモジュールがカーネルに組み込まれるように make menuconfig でconfigを修正してみてください。
configを修正したらビルドして起動を確認します。
lsmodで何も表示されなくなるまで、これを繰り返します。
lsmodで何も表示されなくなったら、qemuの -initrd オプションをはずして起動してみてください。うまく立ち上がれば成功です。
$ qemu-system-arm -M versatilepb \ -kernel zImage \ -hda hda.img.qcow2 \ -append "root=/dev/sda1"
カーネルとinitrdをDebianのパッケージ管理からはずす。
もはや、カーネルは自分で自由に変更するので、Debianのパッケージの管理下にある必要がありません。
apt-get upgrade したときに自分の変更と衝突してエラーになったりするので、該当するDebianのパッケージを削除してしまいます。
armel$ su # apt-get remove initramfs-tools # apt-get autoremove
/boot も /lib/modules もディレクトリごと無くなりました。これらは必要に応じて自分で作るようにします。
これでカーネルとユーザーランドの依存関係が疎になりました。
積極的にカーネルをいじって試してみましょう。