採用情報

お問い合わせ

BLOG

IoT 技術コラム

2024 年 06 月 07 日

EMLinux 3.0 を Raspberry Pi 4B へ移植するには

はじめに

本記事では、2023 年 8 月に実施した EMLinux 3.0 ( 以下、 EMLinux) の Raspberry Pi 4B ( 以下、 RPi4) への移植の作業手順についてまとめています。 この作業の成果は、最終的に GitHub へのプルリクエスト (Pull Request 以下、 PR) によって meta-emlinux へと取り込まれました。今回は、その PR までの道筋を簡単に紹介します。

EMLinux は開発モデルにレイヤーモデルを採用しています。このモデルでは、ベンダーやユーザーのカスタマイズ情報をレイヤーという単位で分離し、モジュール化します。今回の移植は EMLinux のレイヤー (meta-emlinux) に RPi4 向けのをサポートするレシピを盛り込むことで実現しています。

今回は、大きく分けて以下の手順で作業を進めました。

  1. Raspberry Pi 3B+ ( 以下、 RPi3) 用のレシピを分析し、 RPi4 への移植に必要な変更を絞り込む。
  2. RPi3 のレシピから、RPi4 レシピのひな形を作成する。
  3. その RPi4 レシピに変更を加える。

1. RPi3 レシピの分析

まず、既存のレシピの分析を行いました。 EMLinux では RPi3 のサポートがすでに取り込まれており、このレシピを参考にすることが近道だと考えられました。
そして、 RPi3 レシピの分析として RPi3 へのサポートを追加した PR の内容を確認しました。

この PR の内、今回の作業に関連がある部分を列挙してみます。

ここまでで、移植に必要な作業をある程度絞り込むことができました。上記のファイルやその中の変数を変更することで、 RPi4 への移植を進めます。

2. ひな形となるターゲットの作成

まずは、ひな形となるターゲットの作成です。今後の作業は、ここで作成したターゲットに変更を加える形で作業を進めます。
今回は、 conf/machine/raspberrypi3bplus-64.conf をコピーし、 conf/machine/raspberrypi4b-64.conf とします。同様に、 conf/machine/raspberrypi3-64.inc をコピーし、 conf/machine/raspberrypi4-64.inc とします。

conf/machine/raspberrypi4b-64.conf から conf/machine/raspberrypi4-64.inc を include するよう、前者のファイルを編集します。

変更前 ( conf/machine/raspberrypi3bplus-64.conf より ):

include conf/machine/raspberrypi3-64.inc

変更後 ( conf/machine/raspberrypi4b-64.conf より ):

include conf/machine/raspberrypi4-64.inc

ターゲットのファイルを作成したことにより、 conf/local.conf で raspberrypi4b-64 をターゲットに指定できるようになりました。

MACHINE = "raspberrypi4b-64"

もちろん、これはあくまで名目上に過ぎません。この状態でビルドを行っても、 RPi3 のイメージがビルドされます。

次から、いよいよ このレシピを実態に合うように変更していきます。

3. ファームウェア関連の設定変更

まずは、RPi4 のファームウェアについてです。

前提として、 RPi3 および RPi4 向け EMLinux は u-boot からカーネルを起動します。そのため、まずはファームウェアが u-boot を起動するための手順を再検討する必要があります。

ここで注意が必要なことは、 RPi3 と RPi4 ではブートプロセスが一部異なるということです。

RPi3 では、 SD カードの boot パーティションから bootcode.bin を探し、発見できればそれを用いて start.elf をロードし、そこからカーネルをブートする (EMLinux では代わりに u-boot のバイナリを実行 )、という手順を取ります。※1
一方で、 RPi4 では、 EEPROM の内容が読み込まれ、 その後 SD カードの boot パーティション以下の start4.elf がロードされ、そこからカーネルをブートする (EMLinux では u-boot)、という手順になります。 ※2

従って、ファームウェアに関しての設定変更は以下の通りです。

  • bootcode.bin は RPi4 のブートに必要がないため、 boot パーティションから削除する。
  • Boot パーティションの start.elf やその他のファイルを、 start4.elf のような 4 のつく対応ファイルに変更する。

これらをレシピに反映させます。

具体的には、 conf/machine/raspberrypi4b-64.conf の IMAGE_BOOT_FILES 変数の値を変更します。 IMAGE_BOOT_FILES 変数は、 boot パーティションに配置するファイルを指定する変数です。

変更前 ( conf/machine/raspberrypi3-64.inc より ):

IMAGE_BOOT_FILES ?= "${KERNEL_IMAGE} ${DTB_FILES} \
                 	${IMAGE_ROOTFS}/boot/overlays/*;overlays/ \
                 	${IMAGE_ROOTFS}/usr/lib/u-boot/${MACHINE}/u-boot.bin;./ \
                 	${IMAGE_ROOTFS}/boot/boot.scr;./ \
                 	${IMAGE_ROOTFS}/boot/COPYING.linux;./ \
                 	${IMAGE_ROOTFS}/boot/LICENCE.broadcom;./ \
                 	${IMAGE_ROOTFS}/boot/bootcode.bin;./ \
                 	${IMAGE_ROOTFS}/boot/config.txt;./ \
                 	${IMAGE_ROOTFS}/boot/start.elf;./ \
                 	${IMAGE_ROOTFS}/boot/start_cd.elf;./ \
                 	${IMAGE_ROOTFS}/boot/start_db.elf;./ \
                 	${IMAGE_ROOTFS}/boot/start_x.elf;./ \
                 	${IMAGE_ROOTFS}/boot/fixup.dat;./ \
                 	${IMAGE_ROOTFS}/boot/fixup_cd.dat;./ \
                 	${IMAGE_ROOTFS}/boot/fixup_db.dat;./ \
                 	${IMAGE_ROOTFS}/boot/fixup_x.dat;./"

変更後 ( conf/machine/raspberrypi4-64.inc より ):

IMAGE_BOOT_FILES ?= "${KERNEL_IMAGE} ${DTB_FILES} \
                 	${IMAGE_ROOTFS}/boot/overlays/*;overlays/ \
                 	${IMAGE_ROOTFS}/usr/lib/u-boot/${MACHINE}/u-boot.bin;./ \
                 	${IMAGE_ROOTFS}/boot/boot.scr;./ \
                 	${IMAGE_ROOTFS}/boot/COPYING.linux;./ \
                 	${IMAGE_ROOTFS}/boot/LICENCE.broadcom;./ \
                 	${IMAGE_ROOTFS}/boot/config.txt;./ \
                 	${IMAGE_ROOTFS}/boot/start4.elf;./ \
                 	${IMAGE_ROOTFS}/boot/start4cd.elf;./ \
                 	${IMAGE_ROOTFS}/boot/start4db.elf;./ \
                 	${IMAGE_ROOTFS}/boot/start4x.elf;./ \
                 	${IMAGE_ROOTFS}/boot/fixup4.dat;./ \
                 	${IMAGE_ROOTFS}/boot/fixup4cd.dat;./ \
                 	${IMAGE_ROOTFS}/boot/fixup4db.dat;./ \
                 	${IMAGE_ROOTFS}/boot/fixup4x.dat;./"

これで、 u-boot を起動させるための設定が完了しました。

※1
https://www.raspberrypi.com/documentation/computers/raspberry-pi.html#boot-sequence
※2
https://www.raspberrypi.com/documentation/computers/raspberry-pi.html#raspberry-pi-4-and-raspberry-pi-5-boot-flow

4. u-boot 関連の設定変更

次に検討するのは u-boot 関連の設定です。

前述の通り、 EMLinux は u-boot を用いてカーネルをブートしています。 u-boot も、 RPi4 に合わせて一部の設定を変更する必要があります。

RPi3 へのサポートを追加する PR から読み取れる、 u-boot に関連する変更部分を整理すると、以下の通りになります。

  • recipes-bsp/u-boot/u-boot-raspberrypi3bplus-64_2023.04.bb をコピーする。
  • これに対応し、 conf/machine/raspberrypi4b-64.conf 内の変数を変更する。
  • conf/machine/raspberrypi4b-64.conf 内の U_BOOT_CONFIG 変数を変更する。
  • recipes-bsp/rpi-boot-setting/rpi-u-boot-scr.bb で生成されるブートスクリプトを RPi4 向けに変更する。

それぞれを詳しく見ていきます。

recipes-bsp/u-boot/u-boot-raspberrypi3bplus-64_2023.04.bb を見ると、ここではマシン特有の操作がなされていないことが分かります。

#
# Copyright (c) Cybertrust Japan Co., Ltd.
#
# SPDX-License-Identifier: MIT
#

require recipes-bsp/u-boot/u-boot-${PV}.inc

したがって、単純にこのファイルをコピーし、 recipes-bsp/u-boot/u-boot-raspberrypi4-64_2023.04.bb とします。

これに合わせて、 conf/machine/raspberrypi4b-64.conf の一部を変更します。

変更前 ( conf/machine/raspberrypi3bplus-64.conf より ):

IMAGE_INSTALL += "u-boot-raspberrypi3bplus-64"
PREFERRED_PROVIDER_u-boot-raspberrypi3bplus-64 = "u-boot-raspberrypi3bplus-64"

変更後 ( conf/machine/raspberrypi4b-64.conf より ):

IMAGE_INSTALL += "u-boot-raspberrypi4b-64"
PREFERRED_PROVIDER_u-boot-raspberrypi4b-64 = "u-boot-raspberrypi4-64"

次に、 conf/machine/raspberrypi4b-64.conf の U_BOOT_CONFIG 変数を RPi4 向けに変更します。
変数名をターゲットに合わせて U_BOOT_CONFIG:raspberrypi4b-64 とし、その値を u-boot の config ディレクトリ から選択します。今回は、 rpi_4_defconfig を用います。

これをレシピに反映させます。

変更前 ( conf/machine/raspberrypi3bplus-64.conf より ):

U_BOOT_CONFIG:raspberrypi3bplus-64 = "rpi_3_b_plus_defconfig"

変更後 ( conf/machine/raspberrypi4b-64.conf より ):

U_BOOT_CONFIG:raspberrypi4b-64 = "rpi_4_defconfig"

最後に、 recipes-bsp/rpi-boot-setting/rpi-u-boot-scr.bb について検討します。

rpi-u-boot-scr.bb は、 recipes-bsp/rpi-boot-setting/files/boot.cmd を用いて、 u-boot のブートスクリプト (boot.scr) を生成します。

この boot.cmd の内容を確認すると、 bcm2837-rpi-3-b-plus.dtb がハードコードされていることが分かります。

fatload mmc 0 ${kernel_addr_r} Image
fatload mmc 0 ${fdt_addr_r} bcm2837-rpi-3-b-plus.dtb
setenv bootargs dwc_otg.lpm_enable=0 earlyprintk root=/dev/mmcblk0p2 rootfstype=ext4 rootwait
booti ${kernel_addr_r} - ${fdt_addr_r}

これを RPi4 向けの .dtb ファイルで置き換えられるよう、レシピに変更を加えます。
rpi-u-boot-scr.bb レシピ内の do_prepare_build で boot.cmd を生成し、その際に DTB_FILES 変数で指定した値が boot.cmd に書き込まれるようにします。
こうすることで、 boot.cmd で指定する .dtb ファイルを、ターゲットに合わせて動的に指定することが可能になります。

変更前 ( recipes-bsp/rpi-boot-setting/rpi-u-boot-scr.bb より ):

SRC_URI = "file://debian/ file://boot.cmd"

TEMPLATE_FILES = "debian/control.tmpl debian/rules.tmpl"
TEMPLATE_VARS += "DEBIAN_BUILD_DEPENDS"

S = "${WORKDIR}/rpi-u-boot-${PV}"

do_prepare_build() {
	mkdir ${S}
	cp -r ${WORKDIR}/debian ${S}/
	cp ${WORKDIR}/boot.cmd ${S}/

	deb_add_changelog
}

変更後 ( recipes-bsp/rpi-boot-setting/rpi-u-boot-scr.bb より ):

SRC_URI = "file://debian/"

TEMPLATE_FILES = "debian/control.tmpl debian/rules.tmpl"
TEMPLATE_VARS += "DEBIAN_BUILD_DEPENDS"

S = "${WORKDIR}/rpi-u-boot-${PV}"

MMC_DEV_NUM:raspberrypi3bplus-64 = "0"
MMC_DEV_NUM:raspberrypi4b-64 = "1"

do_prepare_build() {
	mkdir ${S}
	cp -r ${WORKDIR}/debian ${S}/

	cat << EOF > ${S}/boot.cmd
part uuid mmc ${MMC_DEV_NUM}:2 uuid
fatload mmc ${MMC_DEV_NUM} \${kernel_addr_r} Image
fatload mmc ${MMC_DEV_NUM} \${fdt_addr_r} ${DTB_FILES}
setenv bootargs dwc_otg.lpm_enable=0 earlyprintk root=PARTUUID=\${uuid} rootfstype=ext4 rootwait
booti \${kernel_addr_r} - \${fdt_addr_r}
EOF

	deb_add_changelog
}

DTB_FILES 変数は、 conf/machine/raspberrypi4b-64.conf で指定されています。
その値を RPi4 用の .dtb ファイル ( bcm2711-rpi-4-b.dtb ) に変更します。

変更前 ( conf/machine/raspberrypi3bplus-64.conf より ):

DTB_FILES = "bcm2837-rpi-3-b-plus.dtb"

変更後 ( conf/machine/raspberrypi4b-64.conf より ):

DTB_FILES = "bcm2711-rpi-4-b.dtb"

以上が u-boot に関連する設定です。

5. カーネルコンフィグの変更

最後に、カーネルコンフィグを変更します。カーネルコンフィグは、ビルド時にカーネルの機能を有効化 / 無効化するための設定です。
ここでも、 RPi3 のカーネルコンフィグ ( recipes-kernel/linux/files/raspberrypi3-64_defconfig ) を元に、 RPi4 向けのカーネルコンフィグを作成します。

さらに具体的には、 raspberrypi3-64_defconfig をコピーした raspberrypi4-64_defconfig に、 meta-raspberrypi の RPi3 と RPi4 の defconfig ( それぞれ、bcmrpi3_defconfig と bcm2711_defconfig) の差分を適用します。

長大なファイルであるため表示しませんが、元となった RPi3 の defconfig と、新しく作成した RPi4 のそれはそれぞれ以下の場所に存在します。

新しく追加した raspberrypi4-64_defconfig が、ビルド時に認識されるよう、 recipes-kernel/linux/linux-cip-rt_git.bb に SRC_URI 変数を追加します。

変更前 ( recipes-kernel/linux/linux-cip_git.bb より ):

SRC_URI:append:qemu-arm64 = " file://qemu-arm64_defconfig"
SRC_URI:append:qemu-amd64 = " file://qemu-amd64_defconfig"
SRC_URI:append:generic-x86-64 = " file://generic-x86-64_defconfig"
SRC_URI:append:raspberrypi3bplus-64 = " file://raspberrypi3-64_defconfig"

変更後 ( recipes-kernel/linux/linux-cip_git.bb より ):

SRC_URI:append:qemu-arm64 = " file://qemu-arm64_defconfig"
SRC_URI:append:qemu-amd64 = " file://qemu-amd64_defconfig"
SRC_URI:append:generic-x86-64 = " file://generic-x86-64_defconfig"
SRC_URI:append:raspberrypi3bplus-64 = " file://raspberrypi3-64_defconfig"
SRC_URI:append:raspberrypi4b-64 = " file://raspberrypi4-64_defconfig"

最後に、 raspberrypi4b-64 ターゲットでは raspberrypi4-64_defconfig を用いるよう、 conf/machine/raspberrypi4-64.inc の KERNEL_DEFCONFIG 変数を変更しておきます。

変更前 ( conf/machine/raspberrypi3-64.inc より ):

KERNEL_DEFCONFIG = "raspberrypi3-64_defconfig"

変更後 ( conf/machine/raspberrypi4-64.inc より ):

KERNEL_DEFCONFIG = "raspberrypi4-64_defconfig"

概ねの流れは以上です。

6. ビルド

ここまでの作業成果は既に meta-emlinux へ反映されています。そのため、 EMLinux 3.0 を Raspberry Pi 3 で動かしてみよう:入門編 の手順に従いビルドが可能です。

RPi3 へのビルドと RPi4 へのビルドとの相違点は、ビルドターゲットの指定方法です。
後者の場合、 conf/local.conf へ以下の内容を追記する必要があります。

MACHINE = "raspberrypi4b-64"

したがって、

$ echo 'MACHINE = "raspberrypi3bplus-64"' >> conf/local.conf

の代わりに、以下のコマンドを実行します。

$ echo 'MACHINE = "raspberrypi4b-64"' >> conf/local.conf

おわりに

EMLinux は、組込み / IoT に適した Linux 環境です。この機会に、お客様製品の組込み Linux の候補としてご検討いただけますと幸いです。
本製品についてのお問い合わせは、以下のリンクよりお願いいたします。

CentOS 7 延長サポートサービス
デジタルトランスフォーメーションのための電子認証基盤 iTrust
SSL/TLS サーバー証明書 SureServer Prime