みつきんのメモ

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

YoctoProject oe-pkgdata-utilを使ってみる

はじめに

YoctoProjectではbitbake以外にもツールを提供している。 その1つにoe-pkgdata-utilが存在する。

パッケージ情報が見れそうなことは伺えるがいまいち使い方がわからない。 今回は逆引き形式で使い方を紹介してみる。

前提

oe-pkgdata-utilはbitbakeにより生成されたパッケージ情報を参照するため、 調べたいパッケージの情報はすでにビルドされている必要がある。

core-image-minimalなどすでにビルド済みである場合は、その時点で作成されているパッケージ情報について調べることができる。

使い方

ビルドしていないパッケージ情報を調べる

まず、調べたいパッケージに関連しそうなレシピがあるかbitbake-layersコマンドを使用して確認する。 その後一度ビルドして、oe-pkgdata-utilを実行する。

vimパッケージを調べたい場合

$ bitbake-layers show-recipes vim
... (snip) ...
=== Matching recipes: ===
vim:
  meta                 9.0.1894

vimのレシピが存在するためビルドする。

$ bitbake vim

パッケージ情報を表示する。

$ oe-pkgdata-util package-info vim
vim 9.0.1894-r0 vim 9.0.1894-r0 4123188

レシピから作成されるパッケージ一覧を取得

list-pkgsサブコマンドを使用する。-pオプションを渡すことでレシピ名を指定することができる。 レシピ名を渡すそのレシピから作成されるすべてのパッケージの一覧が表示される。

$ oe-pkgdata-util list-pkgs -p vim
vim
vim-common
vim-dbg
vim-dev
vim-doc
vim-help
vim-src
vim-syntax
vim-tools
vim-tutor
vim-vimrc

パッケージが提供するファイル一覧を取得

list-pkg-filesを使用する。

$ oe-pkgdata-util list-pkg-files vim-vimrc
vim-vimrc:
    /usr/share/vim/vimrc

パッケージ名から元になるレシピ名を取得

lookup-reciepサブコマンドを使用する。

$ oe-pkgdata-util lookup-recipe vim-vimrc
vim

bitbake-layers show-recipesと組み合わせて、そこからさらにレシピのファイルを探したりもできる。

$ bitbake-layers show-recipes -f vim
... (snip) ...
=== Matching recipes: ===
/home/mickey/seagate/yocto/qemuarm64/poky/meta/recipes-support/vim/vim_9.0.bb

ターゲット上のパスからパッケージ名を取得

find-pathサブコマンドを使用する。

$ oe-pkgdata-util find-path /usr/bin/ex
vim: /usr/bin/ex

ターゲット上には動的に生成されるなどしてパッケージに属しないファイルも存在する。その場合は下記のようにエラーになる。

$ oe-pkgdata-util find-path /var/log/messages
ERROR: Unable to find any package producing path /var/log/messages

パッケージの依存関係を取得

read-valueサブコマンドを使用する。

$ oe-pkgdata-util read-value RDEPENDS vim
desktop-file-utils ncurses-terminfo-base update-alternatives-opkg cairo (>= 1.16.0) gdk-pixbuf (>= 2.42.10) glib-2.0 (>= 2.72.3) glibc (>= 2.35) gtk+3 (>= 3.24.34) libacl (>= 2.3.1) libice (>= 1.0.10) libsm (>= 1.2.3) libx11 (>= 1.7.3.1) libxt (>= 1.2.1) ncurses-libtinfo (>= 6.3+20220423) pango (>= 1.50.4)

レシピにもよるが、RDEPENDS以外にも下記のような変数の値を取得することができる。

まとめ

oe-pkgdata-utilの使い方をまとめた。先にbitbakeを実行してビルドしておく必要はあるものの、 使い方を覚える意外と便利であることがわかった。

YoctoProject Radxa ROCK 4SEを動かしてみる

はじめに

以前から借りっぱなしで放置されているROCK 4SEをYoctoProjectで動かしてみる。

meta-rockchipについて

YoctoProjectで管理されているmeta-rockchipはあまりメンテナンスされていないっぽく、新し目のボードはサポートしていないが、 githubでRadxaが管理しているmeta-rockchipでは新しいボードをサポートしている。

Radxaのリポジトリの方にはrockchip-rk3399-rock-4seのマシン定義がある。

ROCK4 SE用のイメージを作成

Radxaのmeta-rockchipを使用してROCK4 SEを動かす。使用するブランチはkirkstone。

Pokyの取得

作業ディレクトリを作成し、pokyを取得する。

$ mkdir -p ~/yocto/rock4se
$ cd ~/yocto/rock4se
$ git clone git://git.yoctoproject.org/poky.git -b kirkstone

meta-rockchipの取得

Layer Indexで提供されているレイヤではないためbitbake-layers layerindex-fetchは使用せずにgitで取得する。

$ pushd poky
$ git clone https://github.com/radxa/meta-rockchip.git -b kirkstone-radxa
$ popd

環境変数の設定

$ source poky/oe-init-build-env

依存レイヤの追加

meta-rockchipが依存するレイヤを追加する。

$ bitbake-layers layerindex-fetch meta-oe

レイヤの追加

$ bitbake-layers add-layer ../poky/meta-rockchip

local.confの修正

MACHINEにrockchip-rk3399-rock-4seを設定する。 また、bmaptoolを使用できるようにするためにIMAGE_FSTYEPSを変更している。

MACHINE ?= "rockchip-rk3399-rock-4se"
DL_DIR = "${TOPDIR}/../downloads"

IMAGE_FSTYPES:append = " wic.gz wic.bmap"

ビルド

とりあえずcore-image-minimalをビルドしてみる。

$ bitbake core-image-minimal

書き込み

bmaptoolで書き込む。

$ pushd ./
$ sudo bmaptool copy ./tmp/deploy/images/rockchip-rk3399-rock-4se/core-image-minimal-rockchip-rk3399-rock-4se.wic.gz /dev/sdX

/dev/sdXは環境に応じて適宜読み替える。

動作確認

USB-UARTの接続

Radxaのwikiにある接続方法

ピン ROCK 4SE ケーブル
10 RXD TXD
8 TXD RXD
6 GND GND

ケーブルの色はものによるので参考程度に。

シリアルの設定

baudrate: 1500000
data bit: 8
stop bit: 1
parity  : none
flow control: none

上記のwikiにはminicomの設定方法まで親切に記載されている。

他のボードも使用する場合ここまでガチガチに設定すると不便なこともあるので、筆者がminicomを起動する場合下記のようにしている。

$ minicom -b 1500000 -D /dev/ttyUSB0

起動

Poky (Yocto Project Reference Distro) 4.0.12 rockchip-rk3399-rock-4se /dev/ttyFIQ0

rockchip-rk3399-rock-4se login: root
root@rockchip-rk3399-rock-4se:~# uname -a
Linux rockchip-rk3399-rock-4se 5.10.160-rockchip-standard #1 SMP Fri Aug 4 02:10:04 UTC 2023 aarch64 GNU/Linux

まとめ

githubでRadxaが管理しているmeta-rockchipでROCK 4SEを動かしてみた。 まだ、core-image-minimalを動かしただけだが、OSは問題なく動いているようだ。

YoctoProjectが同名のBSPレイヤを提供していて、使用したいボードがサポートされていない場合でもボードのベンダー(今回はRadxa)が提供している方を調べるとサポートされている場合がある。

Radxaのボードに関してはwikiなどもあり、ある程度しっかりとボードの情報が提供されているようだし、IoT本舗が日本語で製品仕様などを発信しているので、比較的使用しやすいかもしれない。

Yocto QEMUのストレージを拡張する(デバイス追加/wic)

はじめに

MACHINE="qemuarm64"などでイメージを作成すると、実機を用意しなくてもYoctoProjectを試せるので便利。 ただ、複数のパーティションを使用したり、ストレージを追加したい場合にぱっとやり方がわからない。 手順を調査したのでメモ。

今回は、ディスクイメージファイルを作成しqemuにデバイスを追加する方法とwicを使用してパーティションを追加する方法を記す。

環境構築

ソース取得

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

環境変数設定

source poky/oe-init-build-env

local.conf

下記の内容をconf/local.confに追加

MACHINE = "qemuarm64"

ビルド

$ bitbake core-image-minimal

qemuの起動

下記のコマンドでqemuを起動できる。

nographicを指定することで、端末の中で起動することができる。VMの出力はシリアルコンソールとして扱われる。 qemu上の文字列などをコピペしたいときなどは便利。

$ runqemu nographic

実際にqemuを起動するにはデバイス構成や、使用するカーネルなど様々な設定をコマンドラインで渡す必要がある。

bitbakeでqemuのイメージを作成するとbuild/tmp/deploy/images/qemuarm64/core-image-minimal-qemuarm64.qemuboot.confというファイルが一緒に生成される。

runqemuで特にオプションが指定されない場合は、このファイルにかかれている情報がqemuに渡されるようになっている。

qemuboot.confの中身

core-image-minimal-qemuarm64.qemuboot.confの内容を見てみる。

[config_bsp]
deploy_dir_image = .
image_link_name = core-image-minimal-qemuarm64
image_name = core-image-minimal-qemuarm64-20230811074446
kernel_imagetype = Image
machine = qemuarm64
qb_cmdline_ip_slirp = ip=dhcp
qb_cmdline_ip_tap = ip=192.168.7.@CLIENT@::192.168.7.@GATEWAY@:255.255.255.0::eth0:off:8.8.8.8
qb_cpu = -cpu cortex-a57
qb_cpu_kvm = -cpu host -machine gic-version=3
qb_default_fstype = ext4
qb_default_kernel = ${@bb.utils.contains("INITRAMFS_IMAGE_BUNDLE", "1", "Image-${INITRAMFS_LINK_NAME}.bin", "Image", d)}
qb_drive_type = /dev/sd
qb_graphics = -device virtio-gpu-pci
qb_machine = -machine virt
qb_mem = -m 256
qb_network_device = -device virtio-net-pci,netdev=net0,mac=@MAC@
qb_opt_append = -device qemu-xhci -device usb-tablet -device usb-kbd -echr 0x14
qb_rng = -object rng-random,filename=/dev/urandom,id=rng0 -device virtio-rng-pci,rng=rng0
qb_rootfs_extra_opt = 
qb_rootfs_opt = -drive id=disk0,file=@ROOTFS@,if=none,format=raw -device virtio-blk-pci,drive=disk0
qb_serial_opt = -device virtio-serial-pci -chardev null,id=virtcon -device virtconsole,chardev=virtcon
qb_smp = -smp 4
qb_system_name = qemu-system-aarch64
qb_tap_opt = -netdev tap,id=net0,ifname=@TAP@,script=no,downscript=no
qb_tcpserial_opt = -device virtio-serial-pci -chardev socket,id=virtcon,port=@PORT@,host=127.0.0.1 -device virtconsole,chardev=virtcon
serial_consoles = 115200;ttyAMA0 115200;hvc0
staging_bindir_native = ../../../work/x86_64-linux/qemu-helper-native/1.0-r1/recipe-sysroot-native/usr/bin
staging_dir_host = ../../../work/qemuarm64-poky-linux/core-image-minimal/1.0-r0/recipe-sysroot
staging_dir_native = ../../../work/qemuarm64-poky-linux/core-image-minimal/1.0-r0/recipe-sysroot-native
tune_arch = aarch64
uninative_loader = ../../../sysroots-uninative/x86_64-linux/lib/ld-linux-x86-64.so.2

メインとなるストレージを指定しているのは以下の部分

qb_rootfs_opt = -drive id=disk0,file=@ROOTFS@,if=none,format=raw -device virtio-blk-pci,drive=disk0

ディスクドライブの指定方法はこれを参考にすれば良さそう。

ストレージの追加を試みる

ディスクイメージファイルの作成

下記のコマンドを実行し、${DEPLOY_DIR_IMAGE}の変数が指す場所にディスクイメージとなるファイルを作成する。

$ pushd ./tmp/deploy/images/qemuarm64/
$ fallocate -l 1G disk.img

qemuboot.confの直接編集

core-image-base-qemuarm64.qemuboot.confの内容を修正しディスクを追加する。 ディスク指定は汎用的なオプション追加のためのqb_opt_appendで行う。

qb_opt_append = -drive id=disk1,file=@DEPLOY_DIR_IMAGE@/disk.img,if=none,format=raw -device virtio-blk-pci,drive=disk1

runqemuではqb_opt_appendを処理する際に「@DEPLOY_DIR_IMAGE@」を見つけると、 bitbakeで参照される${DEPLOY_DIR_IMAGE}が指すディレクトリのパスに置き換えるようになっている。

qemuを起動し、/dev/vdbが認識されていればストレージの追加は成功となる。

$ runqemu nographic
root@qemuarm64:~# ls /dev/vd*
/dev/vda  /dev/vdb

ただし、ストレージデバイスが追加されただけなので、ファイルシステムの作成(mkfs)やマウントなどは手動で行う必要がある。

また、この方法では次回bitbake実行時にこの内容は破棄されてしまう。

local.confでの設定

ディスクイメージファイルを作成した状態でlocal.confに下記の内容を記載する。

QB_OPT_APPEND:append = " -drive id=disk1,file=@DEPLOY_DIR_IMAGE@/disk.img,if=none,format=raw -device virtio-blk-pci,drive=disk1"

これでbitbakeをするたびに追加したストレージが認識しなくなることは避けられる。

qemuでwicを使用する

ストレージを追加する方法では、以下のことを自分で行う必要がある。

これは意外と面倒な作業となる。

ディスクイメージを追加することにこだわらずにパーティションを追加するだけであればwicを使用する方法もある。 この場合、qemu上で/dev/vdbは存在しないが、/dev/vdaがパーティション分割された状態で認識されるようになる。

作業用レイヤの作成

下記のコマンドで作業用レイヤを作成する。

$ bitbake-layers create-layer ./meta-wic-work
$ bitbake-layers add-layer ./meta-wic-work

wksファイルの作成

下記のコマンドでwksの格納場所を作成する。

$ mkdir ./meta-wic-work/wic

meta-wic-work/wic/qemu-wic.wksを下記の内容で作成する。

part / --source rootfs --ondisk vda --fstype=ext4 --label platform --align 1024
part /opt --fstype=ext4 --ondisk vda --label opt --fixed-size=1G

bbclassファイルの作成

qemuqemu-wic.wksを参照し、wicイメージを出力するための設定と、ルートFS上に/optディレクトリを作成する、qemu-wic.bbclassを作成する。

下記のコマンドでbbclassの格納場所を作成する。

$ mkdir ./meta-wic-work/classes

meta-wic-work/classes/qemu-wic.bbclassを下記の内容で作成する。

ROOTFS_POSTPROCESS_COMMAND += "create_opt_dir;"

QB_FSINFO = "wic:no-kernel-in-fs"
QB_KERNEL_ROOT = "/dev/vda1"
QB_DEFAULT_FSTYPE = "wic"
WKS_FILE = "qemu-wic.wks"
IMAGE_FSTYPES += "wic"

create_opt_dir() {
    mkdir ${IMAGE_ROOTFS}/opt
}

local.confの修正

local.confに下記の内容を追加する。

INHERIT += "qemu-wic"

また、QB_OPT_APPEND:appendの行は不要なので削除する。

イメージのビルド及び動作確認

下記コマンドでイメージをビルドしなおす。

$ bitbake core-image-minimal -c cleansstate
$ bitbake core-image-minimal

動作確認

$ runqemu nographic

qemu上で下記を実行し/dev/vda2/optとしてマウントされていることを確認する。

root@qemuarm64:~# mount
/dev/root on / type ext4 (rw,relatime)
devtmpfs on /dev type devtmpfs (rw,relatime,size=116500k,nr_inodes=29125,mode=755)
proc on /proc type proc (rw,relatime)
sysfs on /sys type sysfs (rw,relatime)
debugfs on /sys/kernel/debug type debugfs (rw,relatime)
tmpfs on /run type tmpfs (rw,nosuid,nodev,mode=755)
tmpfs on /var/volatile type tmpfs (rw,relatime)
/dev/vda2 on /opt type ext4 (rw,relatime)
devpts on /dev/pts type devpts (rw,relatime,gid=5,mode=620,ptmxmode=000)

ついでにqemu上の/etc/fstabの内容も確認する。

root@qemuarm64:~# cat /etc/fstab 
# stock fstab - you probably want to override this with a machine specific one

/dev/root            /                    auto       defaults              1  1
proc                 /proc                proc       defaults              0  0
devpts               /dev/pts             devpts     mode=0620,ptmxmode=0666,gid=5      0  0
tmpfs                /run                 tmpfs      mode=0755,nodev,nosuid,strictatime 0  0
tmpfs                /var/volatile        tmpfs      defaults              0  0

# uncomment this if your device has a SD/MMC/Transflash slot
#/dev/mmcblk0p1       /media/card          auto       defaults,sync,noauto  0  0

/dev/vda2   /opt    ext4    defaults    0   0

まとめ

今回は、下記の2つの方法でqemuのストレージを拡張する方法を調べた。

どうしてもディスクデバイスを増やしたい理由がなければwicを使用してパーティションを追加する方法が手軽。 さりげにbbclassの作成方法にも軽く触れておいたので参考になれば。

YoctoProject PREMIRRORとown-mirror

はじめに

LTSではないバージョンのYoctoProjectなどで開発を始めたり、プロダクトで使用したためバージョンを固定する必要があったりして、SRC_URIで取得するソースコードをミラーしたいケースがあると思う。

また、企業のネットワークなどでは、そもそもインターネットへの接続に制限があったり、ソースコードも社内で管理されているミラーサーバからの取得が要求される場合もある。

YoctoProjectでは管理を継続しているがアップストリームがそのバージョンのソースコードの公開をやめてしまうこともある。

そのような色々な事情からYoctoProject(というかOpenEmbeddedのビルドシステム)では、下記の順番でソースコードの参照を試みる。

  1. ローカルのdownloadsディレクト
  2. PREMIRRORSに指定されたURL
  3. アップストリームのソースコードのURL
  4. MIRRORSに指定されたURL

PREMIRRORSはアップストリームのソースコードの前に参照され、MIRRORSはその取得に失敗した場合に参照される。

pokyのPREMIRRORS変数

https://docs.yoctoproject.org/singleindex.html#term-PREMIRRORSには下記のような記載がある。

Assuming your distribution (DISTRO) is “poky”, the default value for PREMIRRORS is defined in the conf/distro/poky.conf file in the meta-poky Git repository.

しかし実際にpoky.confを参照しても直接の記述は見つけられない。

bitbake -eでPREMIRRORSの内容を確認すると下記のように設定されていることが確認できる。

$ bitbake core-image-minimal -e | grep '^PREMIRRORS='
PREMIRRORS=" git://sourceware.org/git/glibc.git https://downloads.yoctoproject.org/mirror/sources/               git://sourceware.org/git/binutils-gdb.git https://downloads.yoctoproject.org/mirror/sources/"

own-mirrors.bbclass

own-mirrorsクラスを使うと、SOURCE_MIRROR_URLに指定したURLを独自のPREMIRRORSとして設定することができるようになる。 PREMIRRORSとSOURCE_MIRROR_URLの違いは、SOURCE_MIRROR_URLには1つしかURLを指定できない事。

https://docs.yoctoproject.org/singleindex.html#own-mirrorsで紹介されているown-mirrorsクラスの使用方法。

INHERIT += "own-mirrors"
SOURCE_MIRROR_URL = "http://example.com/my-source-mirror"

このクラスは独自のミラーを生成することはできない。

own-mirrors向けのミラーの作成手順

local.confに下記の内容を追加する。ここではダウンロード先を${HOME}/downloadsに指定している。

DL_DIR = "${HOME}/downloads"
BB_GENERATE_MIRROR_TARBALLS = "1"

下記コマンドを実行する。

$ bitbake <target> --runonly=fetch

own-mirrorを作ってみる

pokyの取得

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

環境変数の設定

$ source poky/oe-init-build-env

local.conf

MACHINEの設定

とりあえずターゲットとなるマシンを設定する。

MACHINE ?= "qemuarm64"

ミラー作成のための設定

own-mirrorを作成するための設定は下記。 ミラーは${HOME}/downloadsに作成される。

DL_DIR = "${HOME}/downloads"
BB_GENERATE_MIRROR_TARBALLS = "1"
SOURCE_MIRROR_FETCH = "1"

SOURCE_MIRROR_FETCHの行は必ずしも必要ではない。 この設定をするとCOMPATIBLE_MACHINECOMPATIBLE_HOSTの設定によらずに、すべてのソースがフェッチされるようになる。 これはミラーを作成する目的がある場合以外には設定しないように注意が必要となる。

下記コマンドでcore-image-sato-sdkで使用するレシピのすべてのdo_fetchタスクを実行する。 つまり、これでcore-image-sato-sdkで使用するソースのown-mirrorが作成される。

$ bitbake core-image-sato-sdk --runonly=fetch

(2024/02/24 追記)

現状のビルド対象の全てのレシピに対してfetchするには下記のようにworldを指定すると良い。

$ bitbake world --runall=fetch

fetchに関してはrunonlyでもいいと思う。

own-mirrorの参照

同じPCから参照する

作成したown-mirrorがビルドマシンに配置されている場合の手順を示す。 own-mirrorを作成する時のbuildディレクトリを使いまわすとdo_fetchでエラーになるので注意する。

別の端末で下記のコマンドを実行する。

$ source poky/oe-init-build-env build_qemu

local.confに下記を追加する。同じPCのデータを使用していることを確認するためBB_NO_NETWORKを設定する。 このフラグを設定するとbitbakeはネットワークにアクセスしなくなる。

INHERIT += "own-mirrors"
SOURCE_MIRROR_URL = "file://${HOME}/downloads"
BB_NO_NETWORK = "1"

この設定では、SOURCE_MIRROR_URLに設定されたミラーからDL_DIRにデータがダウンロードされる。

あとは普通にbitbakeを実行するとイメージが作成される。

$ bitbake core-image-base

別のPCから参照する

作成したown-mirrorがビルドマシンとは別のPCに配置されている場合の手順を示す。

own-mirrorを他のPCから参照できるようにhttpサーバでディレクトリを公開する。下記では8000番ポートを使用している。

$ cd ~/downloads
$ python3 -m http.server 8000

local.confに下記の内容を追加する。

INHERIT += "own-mirrors"
SOURCE_MIRROR_URL = "http://<IPアドレス>:8000"

IPアドレスが192.168.0.1だった場合下記のようになる。

INHERIT += "own-mirrors"
SOURCE_MIRROR_URL = "http://192.168.0.1:8000"

まとめ

own-mirrorを使用すると、予めダウンロードしてあるディレクトリをPREMIRRORSに追加することができる。 PREMIRRORSはインターネット上のソースコードを探す前に参照されるため、 PREMIRRORSでソースコードが見つかった場合インターネットにアクセスする必要がなくなる。 そのため、ネットワークアクセスに制限がある状態でもbitbakeが可能になる。

予め --runonly=fetchなどでデータをダウンロードしておき、そのディレクトリをSOURCE_MIRROR_URLに指定することで own-mirrorとして使用することができる。

SOURCE_MIRROR_URLに指定したいディレクトリを予めhttpサーバなどで公開することで、 ローカルネットワーク内のミラーサーバのように使用することもできる。

長く続くプロジェクトではPREMIRRORSやown-mirrorを使用することでインターネット上のソースコードの公開が停止されてしまう場合に備えておくと、安心してYoctoProjectを使用することができるかもしれない。

YoctoProject 4.2(mickledore)をラズベリーパイで試す

はじめに

筆者がぼーっと過ごしているうちに、YoctoProject 4.2(mickledore)がリリースされていた。 のみならず、mickledoreは4.2.1として更新されていた。

いい加減試してみる。

環境構築

作業環境

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

pokyの取得

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

環境変数の設定

$ source poky/oe-init-build-env

meta-raspberrypiの取得

$ bitbake-layers layerindex-fetch meta-raspberrypi

local.confを編集

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 = ""

# Accept for the synaptics license
LICENSE_FLAGS_ACCEPTED = "synaptics-killswitch"

ビルド

core-image-baseをビルドする。

$ bitbake core-image-base

書き込み

bmaptoolで書き込む。

$ sudo bmaptool copy core-image-base-raspberrypi4.wic.bz2 /dev/sdX

/dev/sdXは環境に応じて適宜読み替える。

動作確認

mickledoreとして起動したことを確認

raspberrypi4-64 login: root
root@raspberrypi4-64:~# cat /etc/os-release
ID=poky
NAME="Poky (Yocto Project Reference Distro)"
VERSION="4.2.1 (mickledore)"
VERSION_ID=4.2.1
VERSION_CODENAME="mickledore"
PRETTY_NAME="Poky (Yocto Project Reference Distro) 4.2.1 (mickledore)"

まとめ

  • 筆者さぼりがち
  • mickledore試した
  • ラズパイ4では問題なく起動

YoctoProject fitImageを試す

はじめに

バイスツリーとカーネルのイメージが通常別々のファイルとして作成され、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を使用することで比較的簡単にセキュアブートを実現することができる。 セキュアブートについては今後調査していきたい。

YoctoProject u-bootのブートスクリプトを使う

はじめに

u-bootではシステム起動時に決まった順番で処理を自動実行させるために boot.scrやuEnv.txtなどのブートスクリプトを使用することができる。

extlinux.confではカーネルやデバイスツリー、initramfsなどを任意のものに差し替えることはできるが、 それ以外のことはできない。

u-boot自体はデバイスの初期化やネットワーク設定、メモリの読み書きなど様々なことが実行できるようになっている。 通常それらを行う場合はu-bootのコンソールを使用し、コマンドを入力していく。 ブートスクリプトはファイルに予めコマンド列を記述しておくことでそれらの処理を自動的に実行させることができる。

extlinux.confと比較すると、より細かい作業を自動化することができる。

uEnv.txt vs boot.scr

uEnv.txtとboot.scrは基本的に同じ目的で存在している。

uEnv.txtはコマンド列を記述したテキストファイルをそのまま配置すればよく手軽である反面、 すでにdeprecatedとなっており、新規での使用は推奨されない。また、新し目のu-bootではすでに使用不可になっている。

推奨されるのはboot.scrだが、こちらは素となるテキストファイルをmkimageによって変換する必要がある。

# ./tools/mkimage -c none -A arm -T script -d autoboot.cmd boot.scr

YoctoProjectのboot.scr

meta-raspberrypiのアプローチ

先述の通り、boot.scrを作成するにはmkimageによる変換が必要であるため、meta-raspberrypiではrpi-u-boot-scr.bbというレシピが存在しており、その中で次のような処理を行っている。

do_compile() {
    sed -e 's/@@KERNEL_IMAGETYPE@@/${KERNEL_IMAGETYPE}/' \
        -e 's/@@KERNEL_BOOTCMD@@/${KERNEL_BOOTCMD}/' \
        "${WORKDIR}/boot.cmd.in" > "${WORKDIR}/boot.cmd"
    mkimage -A ${UBOOT_ARCH} -T script -C none -n "Boot script" -d "${WORKDIR}/boot.cmd" boot.scr
}

boot.scrを使うだけで、この様なレシピを毎回作成するのは結構面倒な作業と感じてしまう。 実は最近のYoctoProjectのバージョンでは、boot.scrに関する機能が強化され、u-bootにbbappendを作成するだけでboot.scrを作成できるようになっている。

boot.scrの作成手順

作業用レイヤの作成

作業用にmeta-workを作成する。

$ bitbake-layers create-layer -p 20 meta-work
$ bitbake-layers add-layer ./meta-work

boot.cmdの作成

u-bootで自動化したいコマンド列を記述したファイルをboot.cmdという名前で作成する。

setenv bootargs "root=/dev/mmcblk0p2 rootwait rw debug console=${console},${baudrate}";
fatload mmc 0:1 ${loadaddr} zImage;
fatload mmc 0:1 ${fdtaddr} am335x-boneblack.dtb;
bootz ${loadaddr} - ${fdtaddr}

あまり意味はないが、例としてBeagleBone Blackで、カーネル、デバイスツリーを読み込みLinuxを起動する処理を記述している。

bbappendの作成

レシピはrecipetoolを使用して作成できる。

$ 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

実際に作成されたファイルは次のようになっている。スカスカなので公開する場合などは筆者はエディタで整形したりする。

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

FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"

UBOOT_ENV = "boot"

UBOOT_ENV_SUFFIX = "scr"

これでbitbakeを実行するとtmp/deploy/images/beaglebone-yocto/boot.scrが作成される。 fileコマンドで確認するとブートスクリプトが作成されていることがわかる。

$ flie -L tmp/deploy/images/beaglebone-yocto/boot.scr
tmp/deploy/images/beaglebone-yocto/boot.scr: u-boot legacy uImage, , Linux/ARM, Script File (Not compressed), 212 bytes, Mon Jan 10 18:46:34 2022, Load Address: 00000000, Entry Point: 00000000, Header CRC: 0X25DA2A0B, Data CRC: 0X95AF300C

wicイメージに含めるためにlocal.confに下記を追加する。

IMAGE_BOOT_FILES:append = " \
    boot.scr \
"

beaglebone-yoctoの実機で試す場合

beaglebone-yoctoで試す場合は、extlinux.confの生成を回避するために--sourceparams="loader=u-boot"を削除したwksを使用する必要がある。

具体的な手順は下記。

$ 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

詳細は前回を参照。

関連する変数

これらの処理はuboot-config.bbclasssu-boot.incで行われる。

実際には下記の変数が関連しているが、UBOOT_ENV_SUFFIXUBOOT_ENVのみ設定すればよい。

# Additional environment variables or a script can be installed alongside
# u-boot to be used automatically on boot.  This file, typically 'uEnv.txt'
# or 'boot.scr', should be packaged along with u-boot as well as placed in the
# deploy directory.  Machine configurations needing one of these files should
# include it in the SRC_URI and set the UBOOT_ENV parameter.
UBOOT_ENV_SUFFIX ?= "txt"
UBOOT_ENV ?= ""
UBOOT_ENV_SRC_SUFFIX ?= "cmd"
UBOOT_ENV_SRC ?= "${UBOOT_ENV}.${UBOOT_ENV_SRC_SUFFIX}"
UBOOT_ENV_BINARY ?= "${UBOOT_ENV}.${UBOOT_ENV_SUFFIX}"
UBOOT_ENV_IMAGE ?= "${UBOOT_ENV}-${MACHINE}-${PV}-${PR}.${UBOOT_ENV_SUFFIX}"
UBOOT_ENV_SYMLINK ?= "${UBOOT_ENV}-${MACHINE}.${UBOOT_ENV_SUFFIX}"

UBOOT_ENV_SUFFIXがscrに設定された場合、mkimageが実行されるようになっている。

    if [ -n "${UBOOT_ENV}" ] && [ "${UBOOT_ENV_SUFFIX}" = "scr" ]
    then
        ${UBOOT_MKIMAGE} -C none -A ${UBOOT_ARCH} -T script -d ${WORKDIR}/${UBOOT_ENV_SRC} ${WORKDIR}/${UBOOT_ENV_BINARY}
    fi

まとめ

  • u-bootでブートスクリプトを使用すると便利
  • uEnv.txtはdeprecated
  • boot.scrはmkimageで作成する必要があるが、YoctoProjectでは比較的簡単に導入できる