はじめに
Raspberry Pi 3 (Raspbian Jessie)を対象とします.別に用意したLinuxマシンを使ってカーネルをクロスコンパイルします.別のLinuxマシンが無い場合は,Raspberry Pi上でコンパイルすることもできると思いますが,かなり時間がかかるはずです.ここでは,Ubuntu16.04 (64bit)をインストールしたマシンが手元にあると思って話を進めます.Raspberry Piは有線でLANに繋げてください.
準備
もし,Raspbianをインストールした直後なら,以下のコマンドでシステムを更新しておく.
sudo apt-get update
sudo apt-get upgrade -y
sudo apt-get dist-upgrade -y
カーネルのソースとRT Preemptパッチのダウンロード
カーネルのバージョンとパッチのバージョンは,マイナーバージョンの番号(最初の数字とドットの後の次の数字)まで合わせる必要がある.
現在のRaspbianのカーネルバージョンを知りたい場合は,Raspberry Piにログインしてターミナルを開いて,
uname -a
を打てば確認できます.
RT Preemptのパッチですが,実は全てのバージョンにパッチが用意されている訳ではないみたいです.ですので,とりあずパッチの方から選ぶのが良いです.パッチは,
に置かれているので,バージョン番号を選び,その中に"patch-$x.$y.-rt.patch.gz"という名前のファイルが有ることを確認して下さい."*"の部分の番号も後で使うのでメモっておいて下さい.
続いてカーネルのソースを手に入れます.
にアクセスし,"Branch:"のプルダウンメニューを展開して,さっき確認したパッチのバージョン番号"$x.$y"に該当するバージョン番号を持つカーネルのソースがあることを確認して下さい.ブランチ名は,"rpi-$x.$y.y"という感じだと思います.
では早速,それぞれを手元にダウンロードしたいと思います.Linuxマシン側にログインし,以下を実行して下さい.
cd
git clone -b rpi-$x.$y.y --depth 1 https://github.com/raspberrypi/linux.git
cd linux
wget https://www.kernel/org/pub/linux/kernel/projects/rt/$x.Xy/patch-$x.$y.*-rt*.patch.gz
zcat patch-$x.$y.*-rt*.patch.gz | patch -p1
"*"の部分は,先にメモっておいた数字を入れて下さい.エラーがでちゃったら失敗です.他のバージョンを試してみるのが良いでしょう.エラーが出なければ,~/linux/の中にRT Preemptのパッチがあたったカーネルのソースが準備されたことになります.
クロスコンパイラなどの準備
お次は,パッチのあたったカーネルのソースをコンパイルするための準備です.Linuxマシン側で以下を実行して下さい(usernameの部分は,自分の環境に合わせて下さい).もし,Raspberry Pi上でコンパイルするなら,クロスコンパイラを準備する必要はありません.次にカーネルオプションをRaspberry PiからLinuxに引き継ぐ部分が出てきますが,そこで,オプションをmodprobeで取り出し,解凍して.configを作った後,Raspberry Pi側に保存されたパッチのあたったソースのディレクトリ(~/linux/)に入れてmenuconfigに進んで下さい.
cd
git clone https://github.com/raspberrypi/tools.git -depth 1
export ARCH=arm
export CROSS_COMPILE=/home/username/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin/arm-linux-gnueabihf-
export INSTALL_MOD_PATH=/home/username/rtkernel
export KERNEL=kernel7
もし,使っているLinuxマシンが32bitであれば,環境変数"CROSS_COMPILE"を設定するところで,"-x64"を消す必要があります.あと,最後の"KERNEL"に代入しているkernel7という値は,Raspberry Pi 3用のカーネルを示す値です.今後,更に新しいハードウェアが出てきた際には,ここを変える必要が出てくると思います.
カーネルオプションの設定
ここは,一歩間違うと悲惨なことになる箇所です.Raspberry Pi側とLinux側を行き来する必要があり,少しややこしいので注意して進めて下さい.もし,どっかの手順でつまづいて,それをはしょったとすると,高確率で失敗するので,その時はWebで十分に情報を探して下さい.
Raspberry Pi側で:
cd
sudo modprobe configs
Linux 側で:
cd
cd linux
scp $(user)@$(host or IP):/proc/config.gz ./
zcat config.gz > .config
$(user)と$(host or IP)の部分は,各自の環境に合わせて下さい.次は細かな設定です.Linux側で,
cd
cd linux
make menuconfig
とすると,ターミナル内に設定画面が出てきます.以下を設定して下さい.
- CONFIG_PREEMPT_RT_FULL
Kernel Features ---->
Preemption Model (Fully Preemptible Kernel (RT)) ---->
Fully Preemptible Kernel (RT) - Enable HIGH_RES_TIMERS
General setup ---->
Timers subsystem ---->
High Resolution Timer Support
2つ目の項目はデフォルトで設定されると思いますが念のため.Saveするのを忘れがちなので気をつけて下さい.
首尾よく終わったらカーネルコンパイルの準備完了です.
カーネルコンパイル
カーネルをコンパイルしていきます.Linux側で以下を実行して下さい.
cd
cd linux
make zImage modules dtbs
make modules_install
mkdir $INSTALL_MOD_PATH/boot
./scripts/mkknlimg ./arch/arm/boot/zImage $INSTALL_MOD_PATH/boot/$KERNEL.img
cp ./arch/arm/boot/dts/*.dtb $INSTALL_MOD_PATH/boot/
cp -r ./arch/arm/boot/dts/overlays $INSTALL_MOD_PATH/boot/
cd $INSTALL_MOD_PATH
tar czf /tmp/kernel-$x.$y.*-rt*-v7+.tgz *
最後のtarで,"kernel-"に続く*は,パッチやカーネルのリビジョン番号などに合わせ,最後の*は*のままにして下さい./tmp/以下にできたkernel-*.tgzファイルは,RT PreemptパッチがあたったRaspbianカーネルそのものです.複数のRaspberry Pi 3に使えるものなので,一度作ったら,ここまでは手順をとばせるようになります.
カーネルの置換
コンパイルしたカーネルをRaspberry Piに導入します.まずはLinux側で以下を実行し,Raspberry Pi側にカーネルを送って下さい.
scp /tmp/kernel-$x.$y.*-rt*-v7+.tgz $(user)@$(host or IP):/tmp
続いてRaspberry Pi側での作業です.
cd /tmp
tar xzf kernel-$x.$y.*-rt*-v7+.tgz
sudo rm -r /lib/firmware/
sudo rm -r /boot/overlays/
cd boot
sudo cp -rd * /boot/
cd ../lib
sudo cp -dr * /lib/
cd /boot
vim cmdline.txt
"sdhci_bcm2708.enable_llm=0"という行を末尾に追加
sudo reboot
再起動後,リアルタイムカーネルが使われているかを確認します.
uname -a
で,先程作ったカーネルのバージョンが見れればOKです.
おわりに
以上でインストール作業は終了です.以後,apt-get upgradeなどを実行すると,カーネルのバージョンが戻ってしまうことがあります.ただ,戻ったとしても,コンパイル済みカーネルを保存しておき,カーネルの置換の手順を踏めばまたリアルタイムカーネルにできるので,そこまで恐れる必要はないはずです.