📠

Raspberry Pi 4 用のLinux PREEMPT RT Kernelをビルドする

2023/12/28に公開

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 Kerneltag一覧を見ると、最も新しいタグとして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)が出てこない場合、おそらくパッチの適用に失敗している。)

MenuConfigトップ画面
General Setupのメニュー画面
Preemption Modelの選択画面

その後、保存(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種類

  1. 動作しているRaspberry Pi 4上で適用する
  2. 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