はじめに
デバイスツリーとカーネルのイメージが通常別々のファイルとして作成され、u-bootなどのブートローダに設定して起動するケースが多い。
ブートに必要なファイルが複数存在すると管理が煩雑になるため、1つのファイルにまとまっている方が扱いやすい。
fitImageを使用することで以下のものを結合し1つのファイルとして取り扱えるようになる。
initramfsに関してはカーネルをビルドする場合に結合することもできるが、別々に作成したものをfitImageとして結合することも可能となっている。 今回はそのあたりも実験してみる。
使用するYoctoProjectのバージョンはkirkstone。ターゲットボードはBeagleBone Blackとする。
fitImageについて
fitImageに関する説明は Flattened uImage Tree (FIT) Imagesがわかりやすい。
fitImageを作成するには、its(Image Tree Source)というデバイスツリーの形式で記述されたテキストファイルを作成する。このファイルをmkimageコマンドに与えることによって、itsに従って必要なファイルを1つのファイルに結合する。 結合されたそれぞれのファイルがメモリ上のどの位置にロードされるべきかなどの情報もitsに記述しておく。これによってブートローダはどのデータをどこにロードするのかを判断することができる。
YoctoProjectでのfitImage
local.conf
などのconfファイルで下記のような設定を記述するとbitbakeでfitImageを作成することができる。
KERNEL_IMAGETYPES:append = " fitImage" KERNEL_CLASSES += "kernel-fitimage"
KERNEL_DEVICETREEやUBOOT_LOADADDRESS、UBOOT_ENTRYPOINTなどの変数を参照し、itsも自動的に生成されるようになっている。
実際にfitImageを生成する処理はkernel-fitimage.bbclass
で行われる。
詳細はmegamanualの5.56 kernel-fitimage.bbclassを参照。
環境構築
Pokyの取得
作業ディレクトリの作成し、pokyを取得する。
$ mkdir -p ~/yocto/bbb-kirkstone $ cd ~/yocto/bbb-kirkstone $ git clone git://git.yoctoproject.org/poky.git -b kirkstone
環境変数の設定
$ source poky/oe-init-build-env
作業用レイヤの作成
$ bitbake-layers create-layer -p 20 meta-work $ bitbake-layers add-layer ./meta-work
extlinux.confは使用しないので下記も実行する。
$ mkdir meta-work/wic $ cat << 'EOF' > meta-work/wic/beaglebone-yocto-wo-extlinux.wks part /boot --source bootimg-partition --ondisk mmcblk0 --fstype=vfat --label boot --active --align 4 --fixed-size 32 --use-uuid part / --source rootfs --ondisk mmcblk0 --fstype=ext4 --label root --align 4 --use-uuid bootloader --append="console=ttyS0,115200" EOF $ echo 'WKS_FILE = "beaglebone-yocto-wo-extlinux.wks"' >> conf/local.conf
詳細はYoctoProject u-bootのextlinux.confを使う を参照。
local.conf
MACHINEにbeaglebone-yocto
を設定しfitImageの作成必要な最低限の設定を追加する。
MACHINE ?= "beaglebone-yocto" DL_DIR = "${TOPDIR}/../downloads" KERNEL_IMAGETYPES:append = " fitImage" KERNEL_CLASSES += "kernel-fitimage" KERNEL_DEVICETREE:beaglebone-yocto = "am335x-boneblack.dtb"
fitImageに組み込むデバイスツリーを限定するために、KERNEL_DEVICETREEEを設定している。
ビルド
とりあえずcore-image-minimalを作成する。
$ bitbake core-image-minimal
起動確認
boot.scrの作成
fitImageを使用するためにu-bootのブートスクリプトを作成する。
boot.cmdを下記の内容で作成する。
setenv bootargs "root=/dev/mmcblk0p2 rootwait rw debug console=${console},${baudrate}"; fatload mmc 0:1 ${loadaddr} fitimage; bootm;
下記のコマンドを実行しレシピを作成する。
$ recipetool appendsrcfile -W ./meta-work virtual/bootloader ./boot.cmd $ recipetool setvar -r ./meta-work/recipes-bsp/u-boot/u-boot_2022.01.bbappend UBOOT_ENV boot $ recipetool setvar -r ./meta-work/recipes-bsp/u-boot/u-boot_2022.01.bbappend UBOOT_ENV_SUFFIX scr
local.confの修正
イメージにfitImageとboot.scrを組み込むためにlocal.confに下記を追加する。
IMAGE_BOOT_FILES:beaglebone-yocto ?= " \ ${SPL_BINARY} \ u-boot.${UBOOT_SUFFIX} \ fitImage \ boot.scr \ "
これでcore-image-minimalを作り直す。
起動ログ
作成したイメージで実機を起動したときのログ。fitImageで起動していることがわかる。
... (snip) ... ## Loading kernel from FIT Image at 82000000 ... Using 'conf-am335x-bone.dtb' configuration Trying 'kernel-1' kernel subimage Description: Linux kernel Created: 2022-07-14 18:52:26 UTC Type: Kernel Image Compression: uncompressed Data Start: 0x82000124 Data Size: 7845608 Bytes = 7.5 MiB Architecture: ARM OS: Linux Load Address: 0x80008000 Entry Point: 0x80008000 Hash algo: sha256 Hash value: 9832e7accda3fb11285bc751c8963d079e4a21f9a22ab0b32d60496c8309e036 Verifying Hash Integrity ... sha256+ OK ## Loading fdt from FIT Image at 82000000 ... Using 'conf-am335x-bone.dtb' configuration Trying 'fdt-am335x-bone.dtb' fdt subimage Description: Flattened Device Tree blob Created: 2022-07-14 18:52:26 UTC Type: Flat Device Tree Compression: uncompressed Data Start: 0x8277b918 Data Size: 63701 Bytes = 62.2 KiB Architecture: ARM Hash algo: sha256 Hash value: 8248d6abf5e839c5c63bf7fabe2943cd93c70efbdaf9e6db245113012cfc12d0 Verifying Hash Integrity ... sha256+ OK Booting using the fdt blob at 0x8277b918 Loading Kernel Image ... OK Loading Device Tree to 8ffed000, end 8ffff8d4 ... OK Starting kernel ... ... (snip) ... Poky (Yocto Project Reference Distro) 4.0.9 beaglebone-yocto /dev/ttyS0 beaglebone-yocto login:
itsファイル(カーネル+デバイスツリー)
このfitImageを作成する際に自動生成されたitsの抜粋を下記に示す。
カーネルのビルドディレクトリ(linux-beaglebone_yocto-standard-build)に fit-image.its
として作成される。
/dts-v1/; / { description = "Kernel fitImage for Poky (Yocto Project Reference Distro)/5.15.54+gitAUTOINC+441f5fe000_9aabbaa89f/beaglebone-yocto"; #address-cells = <1>; images { kernel-1 { description = "Linux kernel"; data = /incbin/("linux.bin"); type = "kernel"; arch = "arm"; os = "linux"; compression = "none"; load = <0x80008000>; entry = <0x80008000>; hash-1 { algo = "sha256"; }; }; fdt-am335x-bone.dtb { description = "Flattened Device Tree blob"; data = /incbin/("arch/arm/boot/dts/am335x-bone.dtb"); type = "flat_dt"; arch = "arm"; compression = "none"; hash-1 { algo = "sha256"; }; }; ... (snip) ... }; configurations { default = "conf-am335x-bone.dtb"; conf-am335x-bone.dtb { description = "1 Linux kernel, FDT blob"; kernel = "kernel-1"; fdt = "fdt-am335x-bone.dtb"; hash-1 { algo = "sha256"; }; }; ... (snip) ... }; };
initramfsの追加
独立したinitramfs
fitImageにinitramfsを含める。
local.confの修正
local.conf
に次の内容を追加する。
INITRAMFS_IMAGE = "core-image-minimal-initramfs" INITRAMFS_FSTYPES = "cpio.gz" IMAGE_FSTYPES_pn-${INITRAMFS_IMAGE} = "${INITRAMFS_FSTYPES}" INITRAMFS_SCRIPTS = "\ initramfs-framework-base \ initramfs-module-debug \ "
fitImageをinitramfs付きのものに変更するために下記も修正する。
IMAGE_BOOT_FILES:beaglebone-yocto ?= " \ ${SPL_BINARY} \ u-boot.${UBOOT_SUFFIX} \ - fitImage \ + fitImage-${INITRAMFS_IMAGE}-${MACHINE}-${MACHINE};fitImage \ boot.scr \ "
起動ログ
この状態でイメージを作り直して起動する。
## Loading kernel from FIT Image at 82000000 ... Using 'conf-am335x-boneblack.dtb' configuration Trying 'kernel-1' kernel subimage Description: Linux kernel Created: 2022-07-14 18:52:26 UTC Type: Kernel Image Compression: uncompressed Data Start: 0x82000124 Data Size: 7849952 Bytes = 7.5 MiB Architecture: ARM OS: Linux Load Address: 0x80008000 Entry Point: 0x80008000 Hash algo: sha256 Hash value: e1afb1b3dd372fca45fc86e061ae7b9323efe864e51fe6d4ce30cd79ef38c606 Verifying Hash Integrity ... sha256+ OK ## Loading ramdisk from FIT Image at 82000000 ... Using 'conf-am335x-boneblack.dtb' configuration Trying 'ramdisk-1' ramdisk subimage Description: core-image-minimal-initramfs Created: 2022-07-14 18:52:26 UTC Type: RAMDisk Image Compression: uncompressed Data Start: 0x8278d13c Data Size: 2555385 Bytes = 2.4 MiB Architecture: ARM OS: Linux Load Address: 0x88080000 Entry Point: 0x88080000 Hash algo: sha256 Hash value: a7a1fe20b206c9f1cdeec6c143c9289c0feab287d220d8f3720a361f92e453f1 Verifying Hash Integrity ... sha256+ OK Loading ramdisk from 0x8278d13c to 0x88080000 ## Loading fdt from FIT Image at 82000000 ... Using 'conf-am335x-boneblack.dtb' configuration Trying 'fdt-am335x-boneblack.dtb' fdt subimage Description: Flattened Device Tree blob Created: 2022-07-14 18:52:26 UTC Type: Flat Device Tree Compression: uncompressed Data Start: 0x8277ca18 Data Size: 67151 Bytes = 65.6 KiB Architecture: ARM Hash algo: sha256 Hash value: aa3212fe1c49bb2b8fa6997043abe1fb37930a58cfdde63b93e3a7b39b6524cd Verifying Hash Integrity ... sha256+ OK Booting using the fdt blob at 0x8277ca18 Loading Kernel Image ... OK Loading Ramdisk to 8fd90000, end 8ffffdf9 ... OK Loading Device Tree to 8fd7c000, end 8fd8f64e ... OK Starting kernel ...
fitImageからinitmrafsもロードしていることが確認できる。
カーネルにバンドルしたinitramfs
カーネル、デバイスツリー、initramfsをそれぞれ別に作成してfitImageとして結合する方法の他に、 予めinitramfsをカーネルにバンドルした状態で作成して、カーネルとデバイスツリーをfitImageとして結合することもできる。
local.confの修正
initramfsをカーネルにバンドルするためにlocal.confに下記を追加する。
INITRAMFS_IMAGE_BUNDLE = "1"
fitImageのファイル名も元に戻す。
IMAGE_BOOT_FILES:beaglebone-yocto ?= " \ ${SPL_BINARY} \ u-boot.${UBOOT_SUFFIX} \ - fitImage-${INITRAMFS_IMAGE}-${MACHINE}-${MACHINE};fitImage \ + fitImage \ boot.scr \ "
起動ログ
作成したイメージで実機を起動したときのログ。
## Loading kernel from FIT Image at 82000000 ... Using 'conf-am335x-boneblack.dtb' configuration Trying 'kernel-1' kernel subimage Description: Linux kernel Created: 2022-07-14 18:52:26 UTC Type: Kernel Image Compression: uncompressed Data Start: 0x82000124 Data Size: 10381632 Bytes = 9.9 MiB Architecture: ARM OS: Linux Load Address: 0x80008000 Entry Point: 0x80008000 Hash algo: sha256 Hash value: cfb1a49a957de9f1712e728ad9e5ef8017d9ccae1e719cb79baa1551df0f1b27 Verifying Hash Integrity ... sha256+ OK ## Loading fdt from FIT Image at 82000000 ... Using 'conf-am335x-boneblack.dtb' configuration Trying 'fdt-am335x-boneblack.dtb' fdt subimage Description: Flattened Device Tree blob Created: 2022-07-14 18:52:26 UTC Type: Flat Device Tree Compression: uncompressed Data Start: 0x829e6b78 Data Size: 67151 Bytes = 65.6 KiB Architecture: ARM Hash algo: sha256 Hash value: aa3212fe1c49bb2b8fa6997043abe1fb37930a58cfdde63b93e3a7b39b6524cd Verifying Hash Integrity ... sha256+ OK Booting using the fdt blob at 0x829e6b78 Loading Kernel Image ... OK Loading Device Tree to 8ffec000, end 8ffff64e ... OK Starting kernel ...
fitImageとしてはカーネルとデバイスツリーだけ読み込まれている。
そして以下のログからカーネルにバンドルされたinitramfsが実行されていることが確認できる。
DEBUG: Loading module debug DEBUG: Running debug_run DEBUG: Calling module hook (post): debug_hook_handler DEBUG: Finished module hook (post): debug_hook_handler DEBUG: Loading module rootfs DEBUG: Calling module hook (pre): debug_hook_handler DEBUG: Finished module hook (pre): debug_hook_handler DEBUG: Running rootfs_run DEBUG: No e2fs compatible filesystem has been mounted, mounting /dev/mmcblk0p2... EXT4-fs (mmcblk0p2): mounted filesystem with ordered data mode. Opts: (null). Quota mode: disabled. DEBUG: Calling module hook (post): debug_hook_handler DEBUG: Finished module hook (post): debug_hook_handler DEBUG: Loading module finish DEBUG: Calling module hook (pre): debug_hook_handler DEBUG: Finished module hook (pre): debug_hook_handler DEBUG: Running finish_run DEBUG: Moving basic mounts onto rootfs DEBUG: Moving /dev, /proc and /sys onto rootfs...
まとめ
下記のものを1つのファイルとして結合できるfitImageを試してみた。
YoctoProjectでは作り方自体は簡単になっている。
fitImageを使用するメリットとしてはブートのために必要なファイルの数を減らすことができることだけではなく、 u-bootに実装されているfitImageの署名検証の機能を使用してセキュアブートさせることもできる。
YoctoProjectではfitImageの署名検証の機能をサポートするための変数などが用意されているため、 fitImageを使用することで比較的簡単にセキュアブートを実現することができる。 セキュアブートについては今後調査していきたい。