Raspberry Pi 4 用のLinux PREEMPT RT Kernelをビルドする
Raspberry Pi 4 でリアルタイム処理を走らせる必要が出てきた。
そのときの、リアルタイムカーネル(PREEMPT RT)をビルドしたときのメモ
環境
ターゲット
Raspberry Pi 4 Model B
ビルドマシン
手元にスペックの良いLinuxマシンがなかったので、 MacBook Air(M1)のDockerDesktop上のUbuntu 22.04で作業した。
コンテナの準備
Dockerホストで実行する
docker run -it --name kbuild ubuntu
ビルド
以下、Dockerコンテナ上での作業。rootでの作業を想定しているため、sudo
はつけていない。
モジュールのインストール
ビルドに必要なモジュールをインストールする。
apt update
apt install -y git bc bison flex libssl-dev make libc6-dev libncurses5-dev wget crossbuild-essential-arm64 kmod
Kernelのclone
Raspberry PiのLinux Kernelのtag一覧を見ると、最も新しいタグとしてstable_20231123
というタグがあったのでこれを使うことにする。
cd ~/
git clone --depth=1 -b stable_20231123 https://github.com/raspberrypi/linux ~/linux
cd ~/linux
head Makefile
で確認したところ、Kernelのバージョンは6.1.63
とのことだった。(6.1はLTSだ。)
VERSION = 6
PATCHLEVEL = 1
SUBLEVEL = 63
PREEMPT RT パッチの適用
PREEMPT RT パッチはココで配布されている。
6.1用のパッチの中で、6.1.63
に近いバージョンを探すと、6.1.67-rt20
という物があったのでこれを使う。(時間が経つと、older
フォルダに移動するようだ)
cd ~/linux
wget https://cdn.kernel.org/pub/linux/kernel/projects/rt/6.1/patch-6.1.67-rt20.patch.gz
zcat patch-6.1.67-rt20.patch.gz | patch -p1
echo $?
最後のecho $?
で0
が表示されたら、パッチを当てるのに成功したということ。
ビルド環境変数の設定
ビルドの環境変数を設定する。公式ページ参照
export CROSS_COMPILE=aarch64-linux-gnu-
export KERNEL=kernel8
export ARCH=arm64
カーネルパラメータの設定
その後、以下のコマンドで。
cd ~/linux
# デフォルトの設定を`.config`ファイルに出力
make bcm2711_defconfig
# UI上で編集する(`.config`ファイルを上書き)
make menuconfig
make menuconfig
では、UIが起動するため、ここでリアルタイムカーネルを設定する。
具体的には、 General setup
に入った後、Preemption Model
を選び、選択肢の中からFully Preemptible Kernel (Real Time)
を選択する。(選択肢にFully Preemptible Kernel (Real Time)
が出てこない場合、おそらくパッチの適用に失敗している。)
その後、保存(Save)し、終了(Exit)する。
ビルド
ビルドする。 4並列(-j4
)でビルドして約15分程でビルドが完了した。
cd ~/linux
make Image modules dtbs -j4
パッケージング
ビルドした状態だと、必要なファイルがあちこちに散らばっているので、ひとまず、 ~/rtkernel/
以下にまとめる。
cd ~/linux
# まとめる先を準備
mkdir -p ~/rtkernel/boot/firmware/overlays
# 必要なファイルをまとめていく
make INSTALL_MOD_PATH=~/rtkernel modules_install
cp arch/arm64/boot/Image ~/rtkernel/boot/firmware/$KERNEL.img
cp arch/arm64/boot/dts/broadcom/*.dtb ~/rtkernel/boot/firmware/
cp arch/arm64/boot/dts/overlays/*.dtb* ~/rtkernel/boot/firmware/overlays/
cp arch/arm64/boot/dts/overlays/README ~/rtkernel/boot/firmware/overlays/
Wi-Fiのモジュールの準備
Raspberry PiのWi-FiモジュールのファームウェアはOSSではないため、別途準備する必要がある。
Wi-Fiを利用しない場合は不要。
cd ~/
git clone --depth 1 https://github.com/RPi-Distro/firmware-nonfree
mkdir -p ~/rtkernel/lib/firmware/
cp -r firmware-nonfree/debian/config/brcm80211/brcm ~/rtkernel/lib/firmware/
tgz圧縮
cd ~/rtkernel/
tar czf ~/kernel.tgz boot/ lib/
ローカルにもってくる
Docker上で作成した必要なファイル一式(kernel.tgz
)をローカルに持ってくる。
docker cp kbuild:/root/kernel.tgz ./
適用
カーネルをRasperry Pi 4に適用する方法は、大別して以下の2種類
- 動作しているRaspberry Pi 4上で適用する
- Raspberry Pi 4 のmicroSDカードをローカルPCでマウントして適用する
MacOS上で作業していると、後者は難しい(ext4なファイルシステムを書き込み可能でマウント)ため、前者で実施した。
後者でもほぼ同じ手順で適用できるはず。
Rasperry Pi 4 にコピー
scpなりで送ってください。
-
/root/kernel.tgz
にファイルを配置 - Rasperry Pi 4上でrootで作業
との前提で以下を記載する。
kernelを適用
# /root/に移動
cd ~/
tar zxvf kernel.tgz
cd rtkernel/
# カーネルの置き換え
rm -rf /lib/firmware/brcm /lib/modules /boot/firmware/overlays
cp -r ./lib/firmware/brcm /lib/firmware/brcm
cp -r ./lib/modules /lib/modules
cp -r ./boot/firmware/overlays /boot/firmware/overlays
cp -r ./boot/firmware/*.btd /boot/firmware/
cp -r ./boot/firmware/kernel8.img /boot/firmware/
SDカードへのアクセスを低レイテンシ設定から除外
vi /boot/cmdline.txt
1行目の行末に sdhci_bcm2708.enable_llm=0
を追記する。
これによりSDカードへのアクセスは低レイテンシモード(Low Latency Mode)が無効となる。(らしいのだが、本当になっているかは未確認)
再起動
この状態で再起動すると、RTパッチを当てたカーネルが起動する。
確認のため、再起動前後でカーネルが変更となることを uname -a
で確認する。
Linux raspberrypi 6.1.0-rpi4-rpi-v8 #1 SMP PREEMPT Debian 1:6.1.54-1+rpt2 (2023-10-05) aarch64 GNU/Linux
reboot
Linux raspberrypi 6.1.63-rt20-v8+ #1 SMP PREEMPT_RT Thu Dec 28 01:12:12 UTC 2023 aarch64 GNU/Linux
再起動後は、カーネルが6.1.63となり、 PREEMPT_RT
との表記もあるため、RTパッチが適用できていることが確認できた。
Discussion