みつきんのメモ

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

YoctoProject ラズベリーパイ4でinitramfs

はじめに

YoctoProjectでinitramfs入門でinitramfsの使用方法を調査した。今回は実機環境でinitramfsを使用してみる。

ターゲットはラズベリーパイ4。使用するブランチはkirkstone。

環境構築

作業環境

$ mkdir -p ~/yocto/rpi-kirkstone
$ cd ~/yocto/rpi-kirkstone

pokyの取得

$ git clone -b kirkstone git://git.yoctoproject.org/poky.git

環境変数の設定

$ source poky/oe-init-build-env

meta-raspberrypiの取得

$ bitbake-layers layerindex-fetch meta-raspberrypi

local.confを編集

meta-raspberrypiでinitramfsをバンドルしたカーネルを作成するための設定はmeta-raspberrypi/docs/extra-build-config.mdに下記のように記載されている。

## Image with Initramfs

To build an initramfs image:

* Set this 3 kernel variables (in kernel's do_configure:prepend in linux-raspberrypi.inc after the line kernel_configure_variable LOCALVERSION "\"\""
)
  - kernel_configure_variable BLK_DEV_INITRD y
  - kernel_configure_variable INITRAMFS_SOURCE ""
  - kernel_configure_variable RD_GZIP y

* Set the yocto variables (e.g. in local.conf)
  - `INITRAMFS_IMAGE = "<name for your initramfs image>"`
  - `INITRAMFS_IMAGE_BUNDLE = "1"`
  - `BOOT_SPACE = "1073741"`
  - `INITRAMFS_MAXSIZE = "315400"`
  - `IMAGE_FSTYPES_pn-${INITRAMFS_IMAGE} = "${INITRAMFS_FSTYPES}"`

これを参考にlocal.confに設定を追加する。kernel_configure_variableについては追加の作業は不要のようだ。

conf/local.confに下記の部分を追加

MACHINE = "raspberrypi4-64"
DL_DIR = "${TOPDIR}/../downloads"

# enable uart
ENABLE_UART = "1"

# systemd
DISTRO_FEATURES:append = " systemd"
VIRTUAL-RUNTIME_init_manager = "systemd"
DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit"
VIRTUAL-RUNTIME_initscripts = ""

# Bundle initramfs
INITRAMFS_IMAGE = "core-image-minimal-initramfs"
INITRAMFS_IMAGE_BUNDLE = "1"
BOOT_SPACE = "1073741"
INITRAMFS_MAXSIZE = "315400"
IMAGE_FSTYPES_pn-${INITRAMFS_IMAGE} = "${INITRAMFS_FSTYPES}"

# fallbackto shell in the initramfs
INITRAMFS_SCRIPTS = "\
                      initramfs-framework-base \
                      initramfs-module-debug \
 "
CMDLINE_DEBUG = "debug shell"

INITRAMFS_IMAGEは前回と同様にcore-image-minimal-initramfsを使用する。 INITRAMFS_SCRIPTSでモジュールを設定。CMDLINE_DEBUGカーネルのブートパラメータを追加している。

使用するカーネルイメージの変更

例によってこのままでは、initramfsをバンドルしたカーネルイメージが作成されるようになるだけで、 wicによって作成されるイメージにはそれは適用されない。

meta-raspberrypiのカーネル

bitbakeで生成されるカーネルイメージは下記のようになっている。

$ pushd ./tmp/deploy/images/raspberrypi4-64/
$ ls -lha Image*
lrwxrwxrwx 2 mickey mickey  80  1月  6 02:08 Image -> Image-1-5.15.34+git0+e1b976ee4f_0086da6acd-r0-raspberrypi4-64-20230105170742.bin
-rw-r--r-- 2 mickey mickey 24M  1月  6 02:08 Image-1-5.15.34+git0+e1b976ee4f_0086da6acd-r0-raspberrypi4-64-20230105170742.bin
-rw-r--r-- 2 mickey mickey 36M  1月  6 02:08 Image-initramfs-1-5.15.34+git0+e1b976ee4f_0086da6acd-r0-raspberrypi4-64-20230105170742.bin
lrwxrwxrwx 2 mickey mickey  90  1月  6 02:08 Image-initramfs-raspberrypi4-64.bin -> Image-initramfs-1-5.15.34+git0+e1b976ee4f_0086da6acd-r0-raspberrypi4-64-20230105170742.bin
lrwxrwxrwx 2 mickey mickey  80  1月  6 02:08 Image-raspberrypi4-64.bin -> Image-1-5.15.34+git0+e1b976ee4f_0086da6acd-r0-raspberrypi4-64-20230105170742.bin

一方で、wicイメージのブートパーティションに書き込まれているカーネルは下記のようになっている。

$ ls -lha | grep kernel 
-rw-r--r--  1 mickey mickey  36M  4月  6  2011 kernel8.img

つまり、カーネルイメージはkernel8.imgという名前にリネームしてコピーされるということになる。

meta-raspberrypi/wic/sdimage-raspberrypi.wksを見るとブートパーティションbootimg-partitionのソースプラグインを使用していることがわかる。

part /boot --source bootimg-partition --ondisk mmcblk0 --fstype=vfat --label boot --active --align 4096 --size 20

このプラグインIMAGE_BOOT_FILES変数によって、インストールするファイルを制御している。 meta-raspberrypiのこの変数の定義はmeta-raspberrypi/conf/machine/include/rpi-base.incで下記のようになっている。

IMAGE_BOOT_FILES ?= "${BOOTFILES_DIR_NAME}/* \
                 ${@make_dtb_boot_files(d)} \
                 ${@bb.utils.contains('RPI_USE_U_BOOT', '1', \
                    '${KERNEL_IMAGETYPE} u-boot.bin;${SDIMG_KERNELIMAGE} boot.scr', \
                    '${KERNEL_IMAGETYPE};${SDIMG_KERNELIMAGE}', d)} \
                 "

実際には下記のように展開される。

$ bitbake -e core-image-minimal | grep '^IMAGE_BOOT_FILES='
IMAGE_BOOT_FILES="bootfiles/*                  bcm2711-rpi-4-b.dtb bcm2711-rpi-400.dtb bcm2711-rpi-cm4.dtb overlay_map.dtb;overlays/overlay_map.dtb at86rf233.dtbo;overlays/at86rf233.dtbo disable-bt.dtbo;overlays/disable-bt.dtbo dwc2.dtbo;overlays/dwc2.dtbo gpio-ir.dtbo;overlays/gpio-ir.dtbo gpio-ir-tx.dtbo;overlays/gpio-ir-tx.dtbo gpio-key.dtbo;overlays/gpio-key.dtbo gpio-poweroff.dtbo;overlays/gpio-poweroff.dtbo gpio-shutdown.dtbo;overlays/gpio-shutdown.dtbo hifiberry-amp.dtbo;overlays/hifiberry-amp.dtbo hifiberry-dac.dtbo;overlays/hifiberry-dac.dtbo hifiberry-dacplus.dtbo;overlays/hifiberry-dacplus.dtbo hifiberry-digi.dtbo;overlays/hifiberry-digi.dtbo justboom-both.dtbo;overlays/justboom-both.dtbo justboom-dac.dtbo;overlays/justboom-dac.dtbo justboom-digi.dtbo;overlays/justboom-digi.dtbo i2c-gpio.dtbo;overlays/i2c-gpio.dtbo i2c-rtc.dtbo;overlays/i2c-rtc.dtbo imx219.dtbo;overlays/imx219.dtbo imx477.dtbo;overlays/imx477.dtbo iqaudio-dac.dtbo;overlays/iqaudio-dac.dtbo iqaudio-dacplus.dtbo;overlays/iqaudio-dacplus.dtbo mcp2515-can0.dtbo;overlays/mcp2515-can0.dtbo mcp2515-can1.dtbo;overlays/mcp2515-can1.dtbo mcp3008.dtbo;overlays/mcp3008.dtbo miniuart-bt.dtbo;overlays/miniuart-bt.dtbo pitft22.dtbo;overlays/pitft22.dtbo pitft28-capacitive.dtbo;overlays/pitft28-capacitive.dtbo pitft28-resistive.dtbo;overlays/pitft28-resistive.dtbo pitft35-resistive.dtbo;overlays/pitft35-resistive.dtbo pps-gpio.dtbo;overlays/pps-gpio.dtbo rpi-ft5406.dtbo;overlays/rpi-ft5406.dtbo rpi-poe.dtbo;overlays/rpi-poe.dtbo vc4-fkms-v3d.dtbo;overlays/vc4-fkms-v3d.dtbo vc4-fkms-v3d-pi4.dtbo;overlays/vc4-fkms-v3d-pi4.dtbo vc4-kms-v3d.dtbo;overlays/vc4-kms-v3d.dtbo vc4-kms-v3d-pi4.dtbo;overlays/vc4-kms-v3d-pi4.dtbo vc4-kms-dsi-7inch.dtbo;overlays/vc4-kms-dsi-7inch.dtbo w1-gpio.dtbo;overlays/w1-gpio.dtbo w1-gpio-pullup.dtbo;overlays/w1-gpio-pullup.dtbo wm8960-soundcard.dtbo;overlays/wm8960-soundcard.dtbo          Image;kernel8.img 

Image;kernel8.imgの行が、カーネルイメージのリネームの部分となることがわかる。つまり下記の部分を修正することで、wicイメージに適用されるカーネルイメージを変更することができる。

${@bb.utils.contains('RPI_USE_U_BOOT', '1', \
   '${KERNEL_IMAGETYPE} u-boot.bin;${SDIMG_KERNELIMAGE} boot.scr', \
   '${KERNEL_IMAGETYPE};${SDIMG_KERNELIMAGE}', d)} \

RPI_USE_U_BOOT変数によってカーネルをu-bootに差し替えるための分岐があるが、今回はu-bootを使用しないので、この部分は無視できる。 この変数はDEPLOY_DIR内のファイル名;wicイメージ内のファイル名という記法になっている。

ここでは、DEPLOY_DIRはbuild/tmp/deploy/images/raspberrypi4-64を指すので、この中にあるinitramfsバンドルのカーネルイメージを指すようにすれば良い。

これらを踏まえるとlocal.confIMAGE_BOOT_FILESを下記のように設定すれば良いことになる。

IMAGE_BOOT_FILES = "${BOOTFILES_DIR_NAME}/* \
                 ${@make_dtb_boot_files(d)} \
               ${KERNEL_IMAGETYPE}-${INITRAMFS_LINK_NAME}.bin;${SDIMG_KERNELIMAGE} \
                 "

${KERNEL_IMAGETYPE}-${INITRAMFS_LINK_NAME}.binを展開するとImage-initramfs-raspberrypi4-64.binになるので、 これがkernel8.imgとしてwicイメージに入るようになる。

動作確認

local.confまとめ

最終的にlocal.confのinitramfs関連の設定は下記のようになる。

INITRAMFS_IMAGE = "core-image-minimal-initramfs"
INITRAMFS_IMAGE_BUNDLE = "1"
BOOT_SPACE = "1073741"
INITRAMFS_MAXSIZE = "315400"
IMAGE_FSTYPES_pn-${INITRAMFS_IMAGE} = "${INITRAMFS_FSTYPES}"

INITRAMFS_SCRIPTS = "\
                      initramfs-framework-base \
                      initramfs-module-debug \
"
CMDLINE_DEBUG = "debug shell"

IMAGE_BOOT_FILES = "${BOOTFILES_DIR_NAME}/* \
                 ${@make_dtb_boot_files(d)} \
               ${KERNEL_IMAGETYPE}-${INITRAMFS_LINK_NAME}.bin;${SDIMG_KERNELIMAGE} \
"

ビルドおよび動作確認

下記でビルドする。

$ bitbake core-image-base

出来上がったwicイメージをSDカードに書き込む。

$ pushd ./tmp/deploy/images/raspberrypi4-64
$ sudo bmaptool copy ./core-image-base-raspberrypi4-64.wic.bz2 /dev/sdX

/dev/sdXは適宜読み替え。

下記のようにログイン前にshが実行されればinitramfsが動作している。

DEBUG: Loading module debug
DEBUG: Running debug_run
DEBUG: Calling module hook (post): debug_hook_handler
Starting shell after debug...
sh: can't access tty; job control turned off
/ #

まとめ

meta-raspberrypiを使用して、ラズベリーパイ4の実機でもinitramfsを使用できることを確認した。 カーネルイメージにinitramfsをバンドルしてしまえば、config.txtなどに追加の設定を行う必要もなく、 initramfsを使用できることがわかった。