そろそろカーネルを弄ってみたい
最近結構Raspberry Piを色々弄っています。
ただ、ソフト的にはほんとにちょっとしたスクリプトをかいているだけで非常に浅いので、もうちょっと深いところもやりたいなと思い、今まで一度もやったことのないカーネルのカスタムにチャレンジしようかなと思い立ちました。
カーネルというのはRaspberry PiのRaspberry Pi OSのずばり核となる部分です。Raspberry Pi OSはOSS(オープンソースソフトウェア)なのでネットで公開されていて自由にソースを弄ってビルド(コンパイル)することができるわけです。カーネルを弄ると普通のアプリではできないような機能を加えたり、逆に普通は削除できない機能を削除して起動を極限まで高速化したり色々できるのです(多分)。ゴイスー。逆にいうと色々出来すぎるが故に、失敗するとRaspberry Piが起動しなくなったり使えなくなる機能が出てきたりします(多分)。
といっても失敗しても特に怒られるわけでもないので、軽い気持ちでカーネルをビルドしてみることにしました。
この後は基本マニアックなので、続き読みたい人だけ続きを読んでください(投げ槍)
カーネル構築
基本的には以下の公式サイトの情報の通りにやるのがよさそうです。ただ英語なのと、少し順番が前後したりしていて自分みたいな初心者には分かりにくいところもあったので、メモ代わりにやったことを記載していきます。
https://www.raspberrypi.com/documentation/computers/linux_kernel.html
まず前提としてカーネルをビルドする方法には、セルフコンパイルとクロスコンパイルがあって、Raspberry Pi2のカーネルの場合だと、カーネルを動かす環境とコンパイル(ビルド)する環境が同じ場合、つまりRaspberry Piでビルドする場合をセルフコンパイルと呼び、カーネルを動かす環境とコンパイル(ビルド)する環境が異なる場合、例えば別のPCでRaspberry Piのカーネルをコンパイル(ビルド)することをクロスコンパイルと呼びます。クロスコンパイルすると、パワーのあるPCを使って早くビルドを完了させることができるのですが、その分ビルドに色々手間が必要となります。今回は最初ということもありますので、Raspberry Piでのセルフコンパイルを実施します。
作業ディレクトリ作成・移動
参考サイトによるとカーネルを置く場所は /usr/local/src
でなく /home/pi
以下が正しいらしいです。なので以下のコマンドで、ホームディレクトリ以下にkernel
というディレクトリ作成して、以下その中で作業します。raspbianのREADMEにも自分がパーミッションを持っているディレクトリに置けって書いてありますね。
$ cd $ mkdir kernel $ cd kernel
カーネルダウンロード
linuxのカーネルを、gitというソフト開発のシステムを用いてダウンロード(clone)。--depth=1
というオプションで最新版だけ持ってきます。カーネルは容量大きいのでオプション付けた方がよいと思います。以下コマンドね。
$ git clone --depth=1 https://github.com/raspberrypi/linux
あとは、よくわからないのですが、bc
というやつを入れないと、カーネルをビルドできないらしいので何も考えずついでにダウンロードしてインストール。
$ sudo apt-get update $ sudo apt-get install bc
カーネルのコンフィギュレーション(Configuration)作成
カーネルをビルドするときの設定を色々弄ります。まずは、以下のコマンドでRaspberry Pi 2のデフォルトのコンフィグ設定を作成します。
$ cd linux $ KERNEL=kernel7 $ make bcm2709_defconfig
上記コマンドで.config
というファイルが生成されます。これがカーネルのビルドの設定が書き込まれたファイルです。RASPBERRY PI 1だとコンフィギュレーション異なるので注意下さい。
カーネルのコンフィギュレーション設定カスタム
カーネルのビルドの設定を変更します。特に設定デフォルトのままでよいのであれば、ここは飛ばして次のカーネルビルドに進んでOKです。
コンフィグファイル(.config)をエディタで直接編集
以下のコマンドでエディタで直接コンフィグファイルを編集できます。
$ vi .config
ただ、設定が膨大で普通の人には難易度が高いので、configファイルを設定する専用ツールを使うのが一般的なようです。
menuconfigでコンフィグファイル設定
コンフィグファイルを設定するツールとしては、menuconfig
がよく使われるようなので使ってみます。menuconfig
使うためにはlibncurses5-dev
というライブラリが必要らしいので以下のコマンドでまずはインストール。
$ sudo apt-get install libncurses5-dev
後は、以下コマンドでmenuconfig
が起動します。
$ make menuconfig
これで、簡単に設定変更できる…といいたいところですが、正直これでも私には難しすぎてチンプンカンプンでした。
aufsとfsprotectで書き込み禁止(read only)化する
折角カーネルビルドするのに、何もしないのは何か勿体ないので今回はシステム全体を書き込み禁止(read only)化してやろうと思います。書き込みできなくして何がうれしいのという感じですが、Raspberry Piの素の状態は要はパソコンなので、いきなり電源を切るとデータが壊れてプログラムが立ち上がらなくなったり、SDにデータをバンバン書いているとSDの書き込み回数の限界に達してこれまたSDが壊れてしまったりと信頼性が低いものなのです、なので組み込み的に使うならシステムを書き込み禁止にしてやることで信頼性を高めることができるわけです。
まずカーネルのバージョンに合わせたaufs
をダウンロードしてインストールしてやる必要があります。当たり前ですが、ダウンロードしたカーネルであって、今動作しているカーネルではないことに注意してください(私はハマってしまいました…)。今回ダウンロードしたカーネルのバージョンは、以下サイトにいくと rpi-4.1.yみたいなことが書いてあるので、4.1なんだと思います。
ダウンロードした後にバージョン確認したい場合は、Makefile
を見るとVERSION = 4, PATCHLEVEL = 1
みたいなことが書いてあるので、ここからバージョンを読み取ってもOKです。
$ git clone https://github.com/sfjro/aufs4-standalone.git $ cd aufs-aufs4-standalone $ git checkout aufs4.1
まずは、以下でカーネルにパッチを当ててやりましょう。patchコマンドを知らない人は調べておくと理解が深まるかもしれません。
$ cd ~/kernel/linux $ patch -p1 < aufs-aufs4-standalone/aufs4-kbuild.patch $ patch -p1 < aufs-aufs4-standalone/aufs4-base.patch $ patch -p1 < aufs-aufs4-standalone/aufs4-mmap.patch
通常はここでエラー無しでパッチ当てが完了します。エラーがでたら、バージョンかディレクトリの配置を疑ってみてください。私はバージョン違いでエラーがでていました。
次に色々必要ファイルを下記コマンドでコピー。
$ cd aufs-aufs4-standalone $ cp -rp fs/ ../ $ cp -rp Documentation/ ../ $ cp -rp include/uapi/linux/aufs_type.h ../include/uapi/linux/
以上が完了したら、以下コマンドでmenuconfig
を起動します。
$ make menuconfig
aufs4のパッチ当てがうまくいっていれば、以下の通りにAufsの設定ができるようになっています。もしAufsが出てこなかったら残念ながらパッチ当てで失敗しています。
File systems -> Miscellaneous filesystems -> Aufs (Advanced multi layered unification filesystem) support (NEW)
Aufsの設定をON(スペースキーで*をつける)してSaveしましょう。.config
に設定が書き込まれます。
カーネルビルド
いよいよお待ちかねのビルド。Raspberry Pi 2だとネット情報だと2時間くらいという噂を聞いていたのですが、実際試すとこれが終わらない終わらない。夜7時にビルド初めて12時回ってもビルド終わらなかったので結局寝てしまい、何時間かかったのかわからずじまいでした。ビルドは夜寝る前にやりましょう。ちなみに時間かかるのはmake zImage modules dtbs
のとこね。
2016/01/11追記:ビルドに時間がかかった理由、makeのオプション指定不足でした。下記本読んで気づきました。追記します。
Makefieの編集
以下コマンドでエディタでMakefile
を開きます。
$ cd ~/kernel/linux
$ vi Makefile
以下好きな名前をつけておきましょう。あとでカスタムしたことがわかるので便利です。
EXTRAVERSION = karaage
カーネルバックアップ
事前にバックアップしておくのがよいかもしれません。そんなんいるか!って人はここは飛ばして次にいきましょう。
$ cd /boot $ sudo mkdir -p boot_org/overlays $ sudo cp *.dtb boot_org/ $ sudo cp overlays/*.dtb boot_org/overlays/ $ sudo cp overlays/README boot_org/overlays/ $ sudo cp kernel7.img boot_org/
カーネルビルド
以下のコマンドでカーネルをビルドして入れ替えましょう。
2016/01/11追記:Raspberry Pi2の場合は1行目を$ make -j4 zImage modules dtbs
とオプションつけることで4コア使えるので4倍ほどビルドが早くなるらしいです。
$ make zImage modules dtbs $ sudo make modules_install $ sudo cp arch/arm/boot/dts/*.dtb /boot/ $ sudo cp arch/arm/boot/dts/overlays/*.dtb* /boot/overlays/ $ sudo cp arch/arm/boot/dts/overlays/README /boot/overlays/ $ sudo scripts/mkknlimg arch/arm/boot/zImage /boot/$KERNEL.img
ちなみにmake
をやり直したいときは、make clean
でなく以下のようにmake mrproper
を使うのがよいみたいです。make clean
との違いは.configure
ファイルまで消してくれるかどうかのもよう。
$ make mrproper
カーネル起動
いよいよ緊張の再起動です。以下のコマンドを震える手で打ちましょう。
$ sudo shutdown -r now
緊張の一瞬…
キターー!!
といっても見分けがつきませんね。以下コマンドを実行して自分がビルドしたバージョンになっていたら成功です。
$ uname -a
自分の場合は以下の通り表示されました。カーネルに自分の名前がついてるってちょっとワクワクですね(自分だけ?)。
Linux <ホスト名> 4.1.7karaage-v7+
fsprotect
ファイルシステムを書き込み禁止(read only)化する仕上げです。書き込み禁止化しない場合は以降は不要です。
まずはfsprotect
のインストール
$ apt-get install fsprotect
以下コマンドでinitrd.img
ファイルを作成
$ sudo update-initramfs -c -k `uname -r`
ファイルが作成できているか確認。
$ ls /boot/initrd*
以下が表示されていたらOK
initrd.img-4.1.7karaage-v7+
次に/boot/config.txt
を編集
$ vi /boot/config.txt
以下追記
initrd.img-4.1.7karaage-v7+
/boot/cmdline.txt
も編集
$ sudo vi /boot/cmdline.txt
以下の通り、最後にfsprotect
を追記
dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p6 rootfstype=ext4 elevator=deadline rootwait fsprotect
再起動
$ sudo shutdown -r now
書き込み禁止になっているか確認。
$ mount
以下のような表示が出てくる。
sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,relatime) proc on /proc type proc (rw,nosuid,nodev,noexec,relatime) udev on /dev type devtmpfs (rw,relatime,size=10240k,nr_inodes=108773,mode=755) devpts on /dev/pts type devpts (rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=000) tmpfs on /run type tmpfs (rw,nosuid,noexec,relatime,size=88296k,mode=755) /dev/mmcblk0p6 on /fsprotect/system type ext4 (ro,relatime,data=ordered) none on /fsprotect/tmp type tmpfs (rw,relatime,size=524288k,mode=755) none on / type aufs (rw,noatime,si=a4f01158) tmpfs on /run/lock type tmpfs (rw,nosuid,nodev,noexec,relatime,size=5120k) tmpfs on /run/shm type tmpfs (rw,nosuid,nodev,noexec,relatime,size=176580k) /dev/mmcblk0p5 on /boot type vfat (rw,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=ascii,shortname=mixed,errors=remount-ro)
参考サイトによると/dev/mmcblk0p6
(本来の root パーティション)が/fsprotect
下にro (read only)
でマウントされていることと、aufs
の記述があることの2点が重要のようなので確認しましょう。ちゃんとなっていますね。
/boot
も保護したい場合は/etc/default/fsprotect
を編集。
$ sudo vi /etc/default/fsprotect
以下を追記すればOK。
PROTECT=”/boot=32M”
これで完了。後はファイルが保護されているか確認しましょう。正しく設定できていれば、どんなにファイルを削除しても作成しても再起動したら元どおりになっているはずです。以下みたいな恐ろしいコマンドをやっちゃっても大丈夫!のはずです(自分はヘタレなのでできませんが)。
$ sudo rm -rf /
aufs+fsprotectを使う意義(2015/10/25追記)
ファイルシステムを書き込み禁止(read only)化するのにaufs+fsprotect
を使う理由というかうれしさが実は今ひとつ分かってなかったのですが、ようやくわかったのでメモ。単純に書き込み禁止にするだけなら、リードオンリーでマウントするように設定すればよいだけなのですが、それだと一切ファイルを作成できなくなってしまうのに対して、aufs+fsprotect
だと、ファイルの一時的な作成やソフトのインストールが可能(ただし電源を切ると元の状態に戻る)ということができるのが利点のようです。UbuntuのLive起動とかはaufs+fsprotect
みたいですね。
単純に書き込み禁止にするなら、例えば以下の記事を参考にすればよさそうです。
Protect your Raspberry PI SD card, use Read-Only filesystem – Charles's Blog
まとめ
カーネルを初めてビルドしてみました。ほぼデフォルトでビルドしただけなのに、ちょっとだけLinuxが分かった的な何の根拠もない自信がついた気がします(大いなる誤解)。しかしRaspberry Pi 2でもビルドに5時間以上かかるのは誤算でした(私のオプション指定不足でした。本文中に追記してあります)。といってもクロスコンパイルできるようなPCが無いので、当分はRaspberry Pi2でセルフコンパイルしようと思います。寝る前に仕掛ければ朝には終わるし。
そしてビルドしたカーネルだと、カメラモジュールが動かなくなりました。/dev/vchiq
というファイルが無くなっているのが原因みたいですが、どうやって直したらいいのか全然わかりません。他にも気づいて無いだけで色々問題あるのかも。うーむ、先は長そうです。
参考リンク
色々参考にしたリンク。ほぼここらへんの情報の寄せ集めです。
カーネルビルド方法
https://www.raspberrypi.org/documentation/linux/kernel/
Raspberry Pi公式。とりあえずここを見るべき
上記記事によると、カーネルの置く場所は/usr/local/src
でなくて/home/pi
以下が正しいらしいです(Raspberry Piのデフォルトの場合)。
aufs+fsprotectで書き込み禁止(Read only)化してファイル保護する方法
Read only化試すきっかけとなった記事
http://www.pc-links.com/blog/raspberrypi/aufs/
カーネルカスタムしないで書き込み禁止(Read only)化してファイル保護する方法
カーネルをビルドし直さなくても書き込み禁止にする方法があるみたいです。unionfs
を使うのが一般的らしいです。今回は試していませんが今後の参考に。手軽にできる一方で、パフォーマンスは低下するらしいです。
Protect your Raspberry PI SD card, use Read-Only filesystem – Charles's Blog
http://lotuseater365.tumblr.com/post/97562640533/raspberry-pi-を-unionfs-fuse-でプロテクトする
カーネルコンフィギュレーション
今後の参考のメモ。今回の記事では特に参考にしていません。