みつきんのメモ

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

YoctoProject wic入門

はじめに

YoctoProjectではbitbakeで生成された成果物をもとに、SDカードなどに直接書き込むことができるディスクイメージを作成するため、 wicというコマンドを提供している。ヘルプにwicは次のようなものだという記載がある。

The 'wic' command generates partitioned images from existing OpenEmbedded build artifacts.

ここでいうOpenEmbedded build artifactsとはbitbakeで生成されたもののことで、下記のようなものを指す。

Image generation is driven by partitioning commands contained in an 'Openembedded kickstart' (.wks) file (see 'wic help kickstart')

イメージはwksファイルに記述されているパーティション情報に基づいて生成される。

the functionality of those scripts is implemented by a general-purpose partitioning 'language' based on Red Hat kickstart syntax

Red Hat kickstartの構文をベースにしているとのこと。

YoctoProject LICHEE RV DOCKを動かすでwksを調べる必要があったので、この際入門してみる。今回はサンプルとして国内に流通していないであろうLICHEE RV DOCKではなく、Raspberry Pi4を扱う。

meta-raspberrypiとwic

wksファイル

wicコマンドは、パーティション構成が定義されているwksファイルを参照する。meta-raspberrypiにはwic/sdimage-raspberrypi.wksというwksファイルが含まれている。

sdimage-raspberrypi.wksは次のようになっている。

# short-description: Create Raspberry Pi SD card image
# long-description: Creates a partitioned SD card image for use with
# Raspberry Pi. Boot files are located in the first vfat partition.

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

このwksからは下記のようなパーティション構成のイメージが作成される。

No マウントポイント FSタイプ ラベル サイズ その他
1 /boot vfat boot 20MiB active
2 / ext4 root

1つ目のパーティションにはactiveの指定がついている。アクティブパーティションによると、この領域からOSが起動される。

wicイメージ

bitbakeを実行するとRaspberry Pi向けのwicイメージが作成されるが、どのようにしてsdimage-raspberrypi.wksが参照されるかを確認する。

$ grep -r 'sdimage-raspberrypi.wks' ./poky/meta-raspberrypi
./conf/machine/include/rpi-base.inc:WKS_FILE ?= "sdimage-raspberrypi.wks"

実装の詳細までは調査していないのだが、IMAGE_FSTYPES変数にwicが設定されている場合にdo_image_wicタスクが実行され、 WKS_FILE変数で指定されたwksファイルがwicコマンドに渡されるという流れになっていると推測される。

meta-raspberrypiのWKS_FILE変数は?=で代入されているためlocal.confで上書き可能となっている。

WKS_FILEに指定されるwksファイルは、レイヤのwicディレクトリに配置されることを期待している。 meta-raspberrypiの場合はsdimage-raspberrypi.wksmeta-raspberrypi/wicに配置されている。

これらのことから自前のwksを適用するためには、下記の手順が必要になることがわかる。

  1. 自作のレイヤにwicディレクトリを用意する
  2. wicディレクトリにwksファイルを作成する
  3. WKS_FILEにwksを設定する

wicコマンドの実行

bitbakeと同様にoe-init-build-envで環境設定を実行することで、wicコマンドを単体で実行することができる。 その場合は、任意のwksファイルを指定することができる。

下記のような内容でtest.wksファイルを作成してみる。

include sdimage-raspberrypi.wks
part /opt --ondisk mmcblk0 --fstype=ext4 --label opt --align 4096 --size 512

wksファイルの記述に関しては後述するが、このwksファイルではsdimage-raspberrypi.wksの内容に加え、新たに512MiBのパーティションを作成し、 /optにマウントされるようにする。ただしマウントポイントは自動的に作成されないため、予めrootfs上にディレクトリを作成しておく必要がある。

part --fstype=ext4 --label opt --align 4096 --size 512

下記のように実行する。

$ wic create ./test.wks -e core-image-base -o output

wicコマンドはビルド済みの成果物を参照するため、先にbitbakeでイメージをビルドしておく必要がある(この例ではcore-image-base)。

outputディレクトリに下記のものが生成されている。

ファイル 内容
debugfs_script
fstab wksの内容を反映するためのfstab
test-202205280913-mmcblk0.direct ディスクイメージ
test-202205280913-mmcblk0.direct.p1 第1パーティションのイメージ
test-202205280913-mmcblk0.direct.p2 第2パーティションのイメージ
test-202205280913-mmcblk0.direct.p3 第3パーティションのイメージ

test-202205280913-mmcblk0.directが生成されたwicイメージで、それ以外のファイルは中間生成物となる。

fstabはルートFSの/etc/fstabと差し替えることで、wksで記述されたパーティション構成をルートFSに反映する。 fstabの差し替えを行いたくない場合には--no-fstab-updateをwicコマンドに渡す。

fstab

wicコマンドで生成された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/mmcblk0p1  /boot   vfat    defaults    0  0
/dev/mmcblk0p3  /opt    ext4    defaults    0  0

/dev/rootカーネルパラメータのroot=に指定されたものを指す。 ファイルシステム上に/dev/root存在しない点に注意。

動作モード

wicコマンドには次の2つの動作モードがある。

  • Raw mode
  • Cooked mode

wicコマンドは内部的に下記のディレクトリを示す変数を参照する。

変数 ディレクトリの概要
ROOTFS_DIR ルートFSを含むディレクトリ(/rootfs)
BOOTIMG_DIR ブート関連ファイルを含むディレクトリ(/EFI、/syslinuxなど)
KERNEL_DIR カーネルを含むディレクト
NATIVE_SYSROOT ホスト上で実行するツールを含むディレクト

Raw modeはこれらの変数を全て手動で指定するモードで、自由度が高い代わりに若干手間がかかる。 Cooked modeは-eで指定したイメージ名から自動的にこれらの変数を設定するモードとなる。

基本的にはCooced modeを使用することになる。

wksファイルの内容

8 OpenEmbedded Kickstart (.wks) Referenceによると、パーティションコマンドは、本家のkickstartが持っている機能のうちの partition(part)とbootloaderしか実装されていない。

先述のsdimage-raspberrypi.wksではpartコマンドしか使用されていない。

bootloaderコマンド

あまり使用されないの省略する。

partitionコマンド

実のところ、partitionコマンドの基本的な構文は下記のバリエーションしかない。

part [moutnpoint]
partition [mountpoint]

[mountpoint]は省略可能で/pathの形式以外ではswapが使用可能。 swapはそのままスワップとして使用される領域となる。

それ以外のオプションについては8.2 Command: part or partitionを参照のこと。

--sourceについて

--sourceオプションは若干特殊となっている。下記の例を取り上げる。

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

これらはパーティションにどのようなファイルを含めるかを指定する。--source rootfsを指定した場合はそのパーティションにルートFSが含まれる。

--source bootimg-partitionを指定した場合は、IMAGE_BOOT_FILES変数に指定されたファイルが含まれる。IMAGE_BOOT_FILESにはブートに必要なファイル群が指定される。

このsourceは単なるオプションではなく、実際にはpluginの指定となる。つまり、各パーティションへのコピー処理はpluginとして実装されていることになる。

これらのプラグインはSource pluginと呼ばれ、poky/scripts/lib/wic/plugins/sourceに格納されているpythonスクリプトで実装されている。

標準では下記のプラグインが提供されている。

  • bootimg-biosplusefi.py
  • bootimg-efi.py
  • bootimg-partition.py
  • bootimg-pcbios.py
  • empty.py
  • isoimage-isohybrid.py
  • rawcopy.py
  • rootfs.py

partコマンドで指定可能とされるオプションの一部は、実行されるSource pluginによっては作用しない。例えば--source rawcopyの場合は対象のパーティションファイルシステムを作成しないため--fstypeは作用しない。 Source pluginの処理内容はそれぞれソースコードを確認するのが一番確実だと考える。

Sourcde pluginは必要に応じて自分で実装することもできる。その際は自分のレイヤのscripts/lib/wic/plugins/source/もしくはlib/wic/plugins/sourceに配置しておくと、wicコマンドがプラグインとして認識することができる。

Source pluginの実装について

先述の通りSource pluginは必要に応じて自分で実装することができる。

Source pluginの条件は下記の通り。

  1. SourcePluginクラスのサブクラスとして実装されている
  2. name変数にユニークな名前が設定されている

まずこの条件を満たせばプラグインとして認識される。

Source pluginはTemplate Methodパターンで実装されているようで、下記のクラスメソッドをサブクラスで一部もしくは全部を実装することで機能を実現する。

メソッド 機能
do_configure_partition ブートローダの設定ファイルの生成など
do_stage_partition 通常は空実装
do_prepare_partition パーティションへのファイルのコピー
do_post_partition パーティションへの署名など
do_install_disk MBRへの書き込みなど

Source pluginの本体は、コピーを実施するdo_prepare_partitionと言っても過言ではない。 どのSource pluginもdo_prepare_partitionは実装することになる。 それ以外のメソッドはブートローダに関連する処理が多く、ブートローダに関連しない場合は実装されないことがある。

これらのクラスメソッドは下記の順序で呼び出される。

この図ではSource pluginで実装されるメソッドの呼び出し順序のざっくりとしたイメージがつかめれば良い。

Source pluginを実装する

KERNEL_DIRに存在するファイルをパーティションにコピーするだけのSource pluginを実装してみる。 rawcopyとは異なり、指定のファイルをファイルシステム上に単純にコピーする。

書式には下記のようになる。

part barebox --source simplecopy --sourceparams="file=vmlinuz" --ondisk mmcblk --fstype=vfat

--sourceparamsの部分をfiles=にしてスペース区切りで複数のファイルをコピーすることもできる。

rootfsプラグインをベースにdo_prepare_partitionメソッドのみ実装している。コピー後のファイルのオーナーに整合性を持たせるために、 __get_pseudoをまるっと借用している。

コメント含めて69行程度でSource pluginが実装できた。

まとめ

wicについて調査した。

wicはRed Hat kickstartをベースにしたwksファイルをもとにパーティション情報を持ったディスクイメージファイルを生成する。 bitbakeで生成されたファイルを扱うことに特化しており、本家のkickstartと比較すると機能は限定的である。

wicはコマンド単体でも実行可能となっており、bitbakeでイメージを生成したあとであれば独自のwksファイルで独自の構成のイメージファイルを生成することも可能となっている。

SourcePluginクラスを継承し、必要なメソッドを実装することで独自のSource pluginを追加することも可能。

wicコマンドのhelpが充実しているので、よく読んでみるといろいろと知らなかった機能が発見できたりする。