みつきんのメモ

組み込みエンジニアです。Interface誌で「Yocto Projectではじめる 組み込みLinux開発入門」連載中

raspberrypi3 yoctoでLinuxカーネル5.0を試す(バニラカーネル編)

はじめに

Linuxカーネル5.0がリリースされたのでmeta-raspberrypiの環境で試そうと思ったら、いろいろと罠があって4日も経ってしまった。

RPiのカーネルこっちで管理されているが、まだ5.0-rc8なのでバニラカーネルを試すことにした。

meta-raspberrypiのカーネルとはバージョンが変わったのでbbappendではなくレシピを新設する。ただし、meta-raspberrypi自体は汚したくないのでmeta-rpi-lk5を新規に作成する。

bbappendはレシピの拡張なのでレイヤをまたいでいても元のレシピの環境変数は引き継がれるため、incファイルなどが元のレイヤにある場合でも正常に処理できるが、 新規に作成するレシピではそれらは引き継がれないため別のレイヤのincを読み込む場合、実行時の環境変数などを考慮する必要がある。

また、今回は無理矢理でも動かす事が目的なので、本格的に使用したい場合はRPi用のカーネルカーネルがリリースされるまで待つことをおすすめする。

環境構築

いつものやつ。

ソース取得

$ mkdir -p rpi-thud/layers
$ cd rpi-thud/layers
$ git clone git://git.yoctoproject.org/poky.git -b thud
$ git clone git://git.yoctoproject.org/meta-raspberrypi -b thud
$ git clone git://git.openembedded.org/meta-openembedded -b thud

環境変数設定

$ source layers/poky/oe-init-build-env build_lk5

自動的にビルドディレクトリに移動される。 これで、bitbake関連のツールが使用可能になる。

レイヤ追加

$ bitbake-layers add-layer ../layers/meta-openembedded/meta-oe
$ bitbake-layers add-layer ../layers/meta-openembedded/meta-python
$ bitbake-layers add-layer ../layers/meta-openembedded/meta-multimedia
$ bitbake-layers add-layer ../layers/meta-openembedded/meta-networking
$ bitbake-layers add-layer ../layers/meta-raspberrypi

local.confの修正

MACHINEの行を修正する。

MACHINE = "raspberrypi3"
DL_DIR ?= "${TOPDIR}/../downloads"

# enable uart
ENABLE_UART = "1"

# systemd
DISTRO_FEATURES_append = " systemd pam"
VIRTUAL-RUNTIME_init_manager = "systemd"
DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit"
VIRTUAL-RUNTIME_initscripts = ""

meta-rpi-lk5の作成

まずはmeta-rpi-lk5を作成し、meta-raspberrypiからカーネルのレシピをlinux-raspberrypi_5.0.bbとしてコピーする。

$ bitbake-layers create-layer meta-rpi-lk5
$ mv ./meta-rpi-lk5 ../layers/
$ mkdir -p ../layers/meta-rpi-lk5/recipes-kernel/linux
$ bitbake-layers add-layer ../layers/meta-rpi-lk5
$ cp ../layers/meta-raspberrypi/recipes-kernel/linux/linux-raspberrypi_4.14.bb ../layers/meta-rpi-lk5/recipes-kernel/linux/linux-raspberrypi_5.0.bb

その後、SRC_URI をバニラカーネルに設定し、バージョンなども5.0向けに設定する。

LINUX_VERSION ?= "5.0.0"

SRCREV = "1c163f4c7b3f621efff9b28a47abb36f7378d783"
SRC_URI = " \
    git://github.com/torvalds/linux.git;protocol=https \
"

require recipes-kernel/linux/linux-raspberrypi.inc

LIC_FILES_CHKSUM = "file://COPYING;md5=bbea815ee2795b2f4230826c0c6b8814"

レシピのカーネルバージョン

local.confで参照するカーネルのバージョンを明示的に設定する。

PREFERRED_VERSION_linux-raspberrypi = "5.0%"

これで5.0を参照しようとする。

incのパス

別のレイヤにあるincファイルを参照する場合は、レイヤのディレクトリをトップとした相対パスで指定する必要がある。 この場合ではmeta-rpi-lk5のレシピからmeta-raspberrypiにあるincファイルを参照したい。

bitbake実行時はレイヤのトップまでは解決されているので、recipes-kernel/linux/linux-raspberrypi.incのように指定する。

filesの参照パス

SRC_URI = "files://"で参照するパスは、実行時のFILESPATHによって解決される。

これはディレクトリ構成に影響されるところなので、レシピではなくlocal.confで対応する。

FILESPATH_append =  ":${TOPDIR}/../layers/meta-raspberrypi/recipes-kernel/linux/files"

defconfigのダウンロード

バニラカーネルではraspberrypi3向けのdefconfigが無い1ので、raspberrypiのカーネルから持ってくる。

SRC_URI = " \
    git://github.com/torvalds/linux.git;protocol=https \
    https://raw.githubusercontent.com/raspberrypi/linux/rpi-5.0.y/arch/arm/configs/bcm2709_defconfig \
"

do_kernel_checkout_append() {
    cp ${WORKDIR}/bcm2709_defconfig ${S}/arch/arm/configs/
}

カスタマイズコードの反映

raspberrypi向けのカスタマイズコードをバニラカーネルに反映する。

とりあえず、ここにLK5に向けて作業中のリポジトリがある(がまだベースが最新ではない)ので、これを引っ張ってきてパッチを作成する。

yocto側のカーネルソースの展開

$ bitbake virtual/kernel -c clean
$ bitbake virtual/kernel -c kernel_checkout

RPiのカーネルの取得

$ mkdir TEMP
$ cd TEMP
$ git clone https://github.com/raspberrypi/linux.git -b rpi-5.0.y
$ cd linux

rsyncで追加分のみ処理したい(更新は除外したい)ので、転送先のファイルのmtimeを更新する。

$ find ../../tmp/work-shared/raspberrypi3/kernel-source/ | xargs touch

rsyncでコピー

$ rsync -rvu ./ ../../tmp/work-shared/raspberrypi3/kernel-source/ --exclude='.git*'

.git関連は除外しておく。

ラズパイ関連のキーワードとしてBCM2835が記述されているファイルをgrepで引っ掛けて上書きコピーをする。

xargsは-Iを使うと後続のコマンドに引数を渡すことができる。ここでは-IXXXとしているので、xargsに渡る引数をXXXとして参照できるようになる。

$ grep -r 'BCM2835' --exclude-dir='.git' . | cut -d':' -f1 | uniq | xargs -IXXX cp -f XXX ../../tmp/work-shared/raspberrypi3/kernel-source/XXX

grepから漏れてて、ビルドに必要なファイルを個別に上書きコピーする。

$ cp ./include/soc/bcm2835/raspberrypi-firmware.h ../../tmp/work-shared/raspberrypi3/kernel-source/include/soc/bcm2835
$ cp ./drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.h ../../tmp/work-shared/raspberrypi3/kernel-source/drivers/staging/vc04_services/bcm2835-camera

ここから一度コミットしてgit format-patchでパッチを作成

$ cd ../..
$ pushd .
$ cd tmp/work-shared/raspberrypi3/kernel-source/
$ git checkout -b test
$ git add .
$ git reset HEAD arch/arm/configs/bcm2709_defconfig
$ git commit -m "Add files for RPi"
$ git format-patch HEAD^
$ mv 0001-Add-files-for-RPi.patch ~/
$ popd

bcm2709_defconfigはSRC_URIで取得するのでパッチからは外す。

レシピにパッチを組み込む

$ mkdir ../layers/meta-rpi-lk5/recipes-kernel/linux/files
$ mv ~/0001-Add-files-for-RPi.patch ../layers/meta-rpi-lk5/recipes-kernel/linux/files/

linux-raspberrypi_5.0.bbのSRC_URIを次のようにした。

SRC_URI = " \
    git://github.com/torvalds/linux.git;protocol=https \
    https://raw.githubusercontent.com/raspberrypi/linux/rpi-5.0.y/arch/arm/configs/bcm2709_defconfig \
    file://0001-Add-files-for-RPi.patch \
"

カーネルのリビルド

カーネルのリビルドは次のコマンドで行なう。

$ bitbake virtual/kernel -c cleansstate
$ bitbake virtual/kernel 

mmcの認識

SDをなぜかmmcblk1と認識するようなので、local.confで対応する。

CMDLINE = "dwc_otg.lpm_enable=0 console=serial0,115200 root=/dev/mmcblk1p2 rootfstype=ext4 rootwait"

イメージの作成

今回はあえて最小構成としてcore-image-minimalを作成する。

$ bitbake core-image-minimal

動作確認

無事に動いた。

Poky (Yocto Project Reference Distro) 2.6.1 raspberrypi3 ttyS0

raspberrypi3 login: root
root@raspberrypi3:~# uname -a
Linux raspberrypi3 5.0.0 #1 SMP Fri Mar 8 05:46:52 UTC 2019 armv7l GNU/Linux

最終的なカーネルのレシピ

linux-raspberrypi_5.0.bb

LINUX_VERSION ?= "5.0.0"

SRCREV = "1c163f4c7b3f621efff9b28a47abb36f7378d783"
SRC_URI = " \
    git://github.com/torvalds/linux.git;protocol=https \
    https://raw.githubusercontent.com/raspberrypi/linux/rpi-5.0.y/arch/arm/configs/bcm2709_defconfig \
    file://0001-Add-files-for-RPi.patch \
"

SRC_URI[md5sum] = "706ffdea63fa9d8525e27d89aa167a31"
SRC_URI[sha256sum] = "42b90e26bb976f29d1fecc669517d16d11d0a8ba58c9040c9e70565a2216f26b"

require recipes-kernel/linux/linux-raspberrypi.inc

LIC_FILES_CHKSUM = "file://COPYING;md5=bbea815ee2795b2f4230826c0c6b8814"

do_kernel_checkout_append() {
    cp ${WORKDIR}/bcm2709_defconfig ${S}/arch/arm/configs/
}

最終的なlocal.conf

自動生成されたlocal.confに次の内容を追加する。

MACHINE = "raspberrypi3"
DL_DIR ?= "${TOPDIR}/../downloads"

# enable uart
ENABLE_UART = "1"

# systemd
DISTRO_FEATURES_append = " systemd pam"
VIRTUAL-RUNTIME_init_manager = "systemd"
DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit"
VIRTUAL-RUNTIME_initscripts = ""

IMAGE_INSTALL_append = " connman connman-client"

PREFERRED_VERSION_linux-raspberrypi = "5.0%"
FILESPATH_append =  ":${TOPDIR}/../layers/meta-raspberrypi/recipes-kernel/linux/files"

#IMAGE_FSTYPES="tar.bz2 ext4 rpi-sdimg"

CMDLINE = "dwc_otg.lpm_enable=0 console=serial0,115200 root=/dev/mmcblk1p2 rootfstype=ext4 rootwait"

KERNEL_DEVICETREE_remove = " \
     overlays/at86rf233.dtbo \
     overlays/dwc2.dtbo \
     overlays/gpio-key.dtbo \
     overlays/hifiberry-amp.dtbo \
     overlays/hifiberry-dac.dtbo \
     overlays/hifiberry-dacplus.dtbo \
     overlays/hifiberry-digi.dtbo \
     overlays/i2c-rtc.dtbo \
     overlays/iqaudio-dac.dtbo \
     overlays/iqaudio-dacplus.dtbo \
     overlays/lirc-rpi.dtbo \
     overlays/pi3-disable-bt.dtbo \
     overlays/pi3-miniuart-bt.dtbo \
     overlays/pitft22.dtbo \
     overlays/pitft28-resistive.dtbo \
     overlays/pitft35-resistive.dtbo \
     overlays/pps-gpio.dtbo \
     overlays/rpi-ft5406.dtbo \
     overlays/rpi-poe.dtbo \
     overlays/vc4-kms-v3d.dtbo \
     overlays/w1-gpio-pullup.dtbo \
     overlays/w1-gpio.dtbo \
"

まとめ

バニラカーネルとRPiカーネルはかなり違う。

キャッシュ周りやデバイスツリー周りなど、注意が必要。

今回は無理矢理でも動かすことがテーマだったので、ほぼRPiカーネル側の修正をバニラに持っていくという力技で対応した。 もうここまで来るとバニラカーネルではない。

[おまけ] overlays以下のデバイスツリーがビルドエラー

次のようにoverlaysのデバイスツリーのビルドで失敗する。

| make[2]: *** No rule to make target 'overlays/at86rf233.dtbo'.  Stop.

Makefileなども見直したが結局うまく行かず。最終的にはoverlaysを諦めた。

そのためにlocal.confに次の行を追加した。

KERNEL_DEVICETREE_remove = " \
     overlays/at86rf233.dtbo \
     overlays/dwc2.dtbo \
     overlays/gpio-key.dtbo \
     overlays/hifiberry-amp.dtbo \
     overlays/hifiberry-dac.dtbo \
     overlays/hifiberry-dacplus.dtbo \
     overlays/hifiberry-digi.dtbo \
     overlays/i2c-rtc.dtbo \
     overlays/iqaudio-dac.dtbo \
     overlays/iqaudio-dacplus.dtbo \
     overlays/lirc-rpi.dtbo \
     overlays/pi3-disable-bt.dtbo \
     overlays/pi3-miniuart-bt.dtbo \
     overlays/pitft22.dtbo \
     overlays/pitft28-resistive.dtbo \
     overlays/pitft35-resistive.dtbo \
     overlays/pps-gpio.dtbo \
     overlays/rpi-ft5406.dtbo \
     overlays/rpi-poe.dtbo \
     overlays/vc4-kms-v3d.dtbo \
     overlays/w1-gpio-pullup.dtbo \
     overlays/w1-gpio.dtbo \
"

OF_OVERLAYの調査

OV_OVERLAYが有効になっていないことに気づいたので掘り下げた。

RPiのカーネルではOF_CONFIGFSによりselectされる。これはbcm2709_defconfigでも設定されている。しかし、バニラカーネルではOF_CONFIGSの機能が実装されていないため結果的にOF_OVERLAYも有効にならない。

OF_CONFIGFSが実装されないのは次のような理由らしい。

I think most of us have given up on making it work in the kernel, just
too many race conditions.

結局、OF_OVERLAYを有効化しても問題は解決しなかった。

Makefileでルールの解決に失敗するのは

./scripts/Makefile.lib./scripts/Makefile.dtbinstが関係していると思ったのだが、これらをyocto側に持っていっても解決できなかった。


  1. 無いわけではないが、使えないっぽいというか試行錯誤の上断念した。