前回 は、QEMU で Arm の組み込み Linux(Buildroot+BusyBox)を動かしました。
今回は、前回の起動について、カーネルのパラメータなど、可能な限り、調査してみたいと思います。
それでは、やっていきます。
はじめに
「QEMUを動かす」の記事一覧です。良かったら参考にしてください。
・第2回:STM32(ARM Cortex-M)をQEMUで動かす(ソースコード確認編)
・第3回:STM32(ARM Cortex-M)をQEMUで動かす(スタートアップルーチン編)
・第4回:STM32(ARM Cortex-M)をQEMUで動かす(リンカスクリプト編)
・第5回:STM32(ARM Cortex-M)のELFファイルの内容を確認する
・第6回:STM32(ARM Cortex-M)のELFファイル⇔バイナリの変換を行う
・第7回:STM32(ARM Cortex-M)のバイナリから構築したELFファイルをQEMUで動かす
・第8回:QEMUのビルドに必要なxpm(xPack Project Manager)について学ぶ
・第9回:QEMUをソースからビルドして動かす
・第10回:QEMUのソースコードを変更してSTM32の動作を変える
・第11回:QEMUに似たRenodeというOSSの組込みデバイスエミュレータを試す
・第12回:QEMUに似たRenodeでSTM32をGDBを使ってデバッグする
・第13回:QEMUに似たRenodeでSTM32をバイナリファイルで動かす
・第14回:QEMUに似たRenodeをソースからビルドする
・第15回:QEMUに似たRenodeでVSCodeを使ってデバッグする
・第16回:QEMUに似たRenodeでVSCodeを使ってRenode自体をデバッグする
・第17回:QEMUで組み込みLinux(Buildroot+BusyBox)をやってみる
・第18回:QEMUで組み込みLinux(Buildroot+BusyBox)をやってみる、の補足 ← 今回
それでは、やっていきます。
start-qemu.shの内容
Buildroot のビルドが完了したら、output/images/start-qemu.sh を実行するだけで Buildroot が起動しました。
start-qemu.sh の内容を確認してみます。まず、全文を貼り付けます。
#!/bin/sh BINARIES_DIR="${0%/*}/" # shellcheck disable=SC2164 cd "${BINARIES_DIR}" mode_serial=false mode_sys_qemu=false while [ "$1" ]; do case "$1" in --serial-only|serial-only) mode_serial=true; shift;; --use-system-qemu) mode_sys_qemu=true; shift;; --) shift; break;; *) echo "unknown option: $1" >&2; exit 1;; esac done if ${mode_serial}; then EXTRA_ARGS='-nographic' else EXTRA_ARGS='-serial stdio' fi if ! ${mode_sys_qemu}; then export PATH="/home/daisuke/svn_/qemu/linux/buildroot-2024.02.3/output/host/bin:${PATH}" fi exec qemu-system-arm -M vexpress-a9 -smp 1 -m 256 -kernel zImage -dtb vexpress-v2p-ca9.dtb -drive file=rootfs.ext2,if=sd,format=raw -append "console=ttyAMA0,115200 rootwait root=/dev/mmcblk0" -net nic,model=lan9118 -net user ${EXTRA_ARGS} "$@"
少しずつ見ていきます。
最初から難しいですね。${0%/*}/ は、${var%word} で、後方一致除去(最短一致)という文法です。変数 ${var} の文字列を末尾から word を探索して、初めて見つけたら、word を含み、末尾まで削除します。
あと、${0} は、実行したコマンドそのものが入るので、今回は、output/images/start-qemu.sh が入ります。最初に / を見つけたら、以降を削除するので、output/images が、BINARIES_DIR にセットされることになります。
その後、start-qemu.sh のあるディレクトリに移動しています。
#!/bin/sh BINARIES_DIR="${0%/*}/" # shellcheck disable=SC2164 cd "${BINARIES_DIR}"
次は、まず、変数に値(false)を設定して、コマンドライン引数のパース処理をしています。
--serial-only が指定されると、mode_serial 変数に true が設定されます。
--use-system-qemu が指定されると、mode_sys_qemu に true が設定されます。
mode_serial=false mode_sys_qemu=false while [ "$1" ]; do case "$1" in --serial-only|serial-only) mode_serial=true; shift;; --use-system-qemu) mode_sys_qemu=true; shift;; --) shift; break;; *) echo "unknown option: $1" >&2; exit 1;; esac done
先ほど設定した2つの変数によって分岐します。
--serial-only が指定されると、EXTRA_ARGS に '-nographic' が設定されて、指定されない場合は、'-serial stdio' が設定されます。
--use-system-qemu が指定されない場合は、output/host/bin がパスに設定されます。なるほど、前回、QEMU をインストールしましたが、Buildroot でビルドした QEMU が使われていたようです。
if ${mode_serial}; then EXTRA_ARGS='-nographic' else EXTRA_ARGS='-serial stdio' fi if ! ${mode_sys_qemu}; then export PATH="/home/daisuke/svn_/qemu/linux/buildroot-2024.02.3/output/host/bin:${PATH}" fi
最後に QEMU で Buildroot を起動するところです。
exec は、同じプロセス内で QEMU を実行するという意味になります(通常はサブプロセスで実行される)。
QEMUのコマンドライン引数
あとは、QEMU のコマンドライン引数です。調べて分かったところだけ書きます。
QEMU の公式ドキュメントのコマンドライン引数の説明のリンクです。
- -M:-machine と同じ意味だと思うのですが、--help にも、QEMU 公式のドキュメントにも記載がありません
- -smp:QEMU の仮想マシンに割り当てる CPU数の指定です
- -m:QEMU の仮想マシンに割り当てるメモリ量(MB単位)です
- -kernel:カーネルイメージの指定です
- -dtb:device tree blob ファイルの指定です
- -drive:仮想マシンに接続するドライブの指定で、今回の場合、ファイル名(file=)は「rootfs.ext2」、インタフェース(if=)は「SDカード」、フォーマット(format=)は「raw」となります
- -append:カーネルに渡すコマンドライン引数(カーネルパラメータ)の指定で、今回の場合、コンソール(console=)は「ttyAMA0 で 115200 の速度で接続」、ルートファイルシステム(=root)は「/dev/mmcblk0 にマウント」となり、rootwait はルートファイルシステムが準備できるまで待機するオプションです
- -net:仮想マシンにネットワーク機能を追加します、今回は nic(Network Interface Card)で、model は品種だと思います、user はホストのインターネット接続の共有です
- -nographic:グラフィカルウィンドウをサポートせず、コマンドラインで起動します
- -serial:仮想シリアルポートを接続します、今回の場合は標準出力です(標準入力も?)
最後に $@ は、start-qemu.sh に指定したコマンドライン引数(上で処理した2つ以外)を QEMU に指定するということだと思います。
ChatGPT に「-M」と「-machine」の違いを聞くと、「-M」は単にマシンタイプを指定するのに対して、「-machine」はマシンタイプに加えて、さまざまな追加オプションを指定することができるそうです。初めて知りました。
exec qemu-system-arm -M vexpress-a9 -smp 1 -m 256 -kernel zImage -dtb vexpress-v2p-ca9.dtb -drive file=rootfs.ext2,if=sd,format=raw -append "console=ttyAMA0,115200 rootwait root=/dev/mmcblk0" -net nic,model=lan9118 -net user ${EXTRA_ARGS} "$@"
start-qemu.sh は以上になります。
start-qemu.shを別のオプションで起動してみる
start-qemu.sh には、2つのオプションがあることが分かりました。
まず、--serial-only を指定して起動してみます。
これによって、QEMU に対して、-serial stdio を指定していたのを、-nographic に変更することになります。
やってみたところ、一見は、同じように起動しただけに見えました。
そこで、--serial-only を指定した場合と、指定しなかった場合で、起動ログを比較してみました。
すると、いくつか違いはあるのですが、--serial-only を指定しなかった場合は、以下のメッセージがありました。
VNC server running on 127.0.0.1:5900
今回起動した Buildroot は、最小構成なので、GUI は無いと思うのですが、一応、VNC サーバが起動されているようです。
実際に、Ubuntu 22.04 に Real VNC をインストールして、127.0.0.1:5900 に接続してみました。
もちろん、GUI のデスクトップなどは見えませんでしたが、接続は出来たようです。

現在の使用方法では、--serial-only を指定する方がいいと思います。
もう1つのオプションは、指定しない場合は、Buildroot でビルドした QEMU を使用しますが、オプションを指定すると、Ubuntu にインストールした QEMU を使えます。違いはあまりないと思うので、試すのは割愛します。
Buildrootのディレクトリ構成
tree コマンドで調べます。2階層に絞っても 3000 以上のディレクトリがありました。
適当にカットしたものを貼り付けます。
$ tree -d -L 2 . |-- arch |-- board | |-- aarch64-efi | |-- bananapi | |-- beagleboardx15 | |-- beaglebone | |-- beagleboneai | |-- beaglev | |-- qemu | |-- raspberrypi | |-- raspberrypi0 -> raspberrypi | |-- raspberrypi0w -> raspberrypi | |-- raspberrypi2 -> raspberrypi | |-- raspberrypi3 -> raspberrypi | |-- raspberrypi3-64 -> raspberrypi | |-- raspberrypi4 -> raspberrypi | |-- raspberrypi4-64 -> raspberrypi | |-- raspberrypicm4io -> raspberrypi | |-- raspberrypicm4io-64 -> raspberrypi | |-- raspberrypizero2w -> raspberrypi | |-- roseapplepi | |-- versal |-- boot | |-- afboot-stm32 | |-- arm-trusted-firmware | |-- at91bootstrap | |-- at91bootstrap3 | |-- at91dataflashboot | |-- barebox | |-- beaglev-ddrinit | |-- beaglev-secondboot | |-- binaries-marvell | |-- boot-wrapper-aarch64 | |-- edk2 | |-- grub2 | |-- mv-ddr-marvell | |-- mxs-bootlets | |-- opensbi | |-- optee-os | |-- s500-bootloader | |-- shim | |-- syslinux | |-- ti-k3-boot-firmware | |-- ti-k3-image-gen | |-- ti-k3-r5-loader | |-- uboot | `-- vexpress-firmware |-- configs |-- dl | |-- (省略) |-- docs | |-- conf | |-- images -> website/images | |-- manual | `-- website |-- fs | |-- cpio | |-- ext2 | |-- initramfs | |-- iso9660 | |-- squashfs | |-- tar |-- linux | `-- 5.10.162-cip24-rt10 |-- output | |-- build | |-- host | |-- images | |-- staging -> /home/daisuke/svn_/qemu/linux/buildroot-2024.02.3/output/host/arm-buildroot-linux-gnueabihf/sysroot | `-- target |-- package | |-- (省略) |-- support | |-- config-fragments | |-- dependencies | |-- docker | |-- download | |-- gnuconfig | |-- kconfig | |-- legal-info | |-- libtool | |-- misc | |-- scripts | `-- testing |-- system | `-- skeleton |-- toolchain | |-- toolchain | |-- toolchain-bare-metal-buildroot | |-- toolchain-buildroot | `-- toolchain-external `-- utils |-- checkpackagelib `-- checksymbolslib 3058 directories
なるほど、たくさんありますね。
ビルドした内容は、すべて output に生成されるとのことなので、output に移動して、output だけを見てみます。
build ディレクトリは数が多かったので省略してます。
$ tree -d -L 2 . |-- build | |-- (省略) |-- host | |-- arm-buildroot-linux-gnueabihf | |-- bin | |-- etc | |-- include | |-- lib | |-- lib64 -> lib | |-- libexec | |-- sbin | |-- share | `-- usr -> . |-- images |-- staging -> /home/daisuke/svn_/qemu/linux/buildroot-2024.02.3/output/host/arm-buildroot-linux-gnueabihf/sysroot `-- target |-- bin |-- dev |-- etc |-- lib |-- lib32 -> lib |-- media |-- mnt |-- opt |-- proc |-- root |-- run |-- sbin |-- sys |-- tmp |-- usr `-- var 93 directories
target ディレクトリが、起動で使用したルートファイルシステムなのかと思ったのですが、target ディレクトリに「THIS_IS_NOT_YOUR_ROOT_FILESYSTEM」というファイルがあります。実際の組み込みシステムで、このルートファイルシステムを使わないでください、とのことでした。
imagesのファイルの作られ方
output/images には、以下のファイルがあります。
$ ll -h images/ 合計 13M drwxr-xr-x 2 daisuke daisuke 4.0K 6月 18 23:15 ./ drwxrwxr-x 6 daisuke daisuke 4.0K 6月 18 23:15 ../ -rw-r--r-- 1 daisuke daisuke 64M 6月 22 22:01 rootfs.ext2 -rwxr-xr-x 1 daisuke daisuke 846 6月 22 16:25 start-qemu.sh* -rwxr-xr-x 1 daisuke daisuke 14K 6月 18 23:15 vexpress-v2p-ca9.dtb* -rw-r--r-- 1 daisuke daisuke 5.1M 6月 18 23:15 zImage
上から順に、ルートファイルシステム、start-qemu.sh、DTB、カーネルです。
ルートファイルシステム、DTB、カーネルが、どこで作られたかを調べておきます。
$ find . -name rootfs.ext2 ./images/rootfs.ext2 $ find . -name zImage ./images/zImage ./build/linux-6.1.44/arch/arm/boot/zImage $ find . -name vexpress-v2p-ca9.dtb ./images/vexpress-v2p-ca9.dtb ./build/linux-6.1.44/arch/arm/boot/dts/vexpress-v2p-ca9.dtb
カーネルと DTB は、output/build/linux-6.1.44 で作られたようです。
ルートファイルシステムは分からなったので、ビルドログから探します。
関係ありそうなログは以下でした。
>>> Generating filesystem image rootfs.ext2 mkdir -p /home/daisuke/svn_/qemu/linux/buildroot-2024.02.3/output/images rm -rf /home/daisuke/svn_/qemu/linux/buildroot-2024.02.3/output/build/buildroot-fs/ext2 mkdir -p /home/daisuke/svn_/qemu/linux/buildroot-2024.02.3/output/build/buildroot-fs/ext2 rsync -auH --exclude=/THIS_IS_NOT_YOUR_ROOT_FILESYSTEM /home/daisuke/svn_/qemu/linux/buildroot-2024.02.3/output/target/ /home/daisuke/svn_/qemu/linux/buildroot-2024.02.3/output/build/buildroot-fs/ext2/target echo '#!/bin/sh' > /home/daisuke/svn_/qemu/linux/buildroot-2024.02.3/output/build/buildroot-fs/ext2/fakeroot echo "set -e" >> /home/daisuke/svn_/qemu/linux/buildroot-2024.02.3/output/build/buildroot-fs/ext2/fakeroot echo "chown -h -R 0:0 /home/daisuke/svn_/qemu/linux/buildroot-2024.02.3/output/build/buildroot-fs/ext2/target" >> /home/daisuke/svn_/qemu/linux/buildroot-2024.02.3/output/build/buildroot-fs/ext2/fakeroot PATH="/home/daisuke/svn_/qemu/linux/buildroot-2024.02.3/output/host/bin:/home/daisuke/svn_/qemu/linux/buildroot-2024.02.3/output/host/sbin:/home/daisuke/.nvm/versions/node/v20.13.1/bin:/home/daisuke/Downloads/xpack-arm-none-eabi-gcc-13.2.1-1.1/bin:/home/daisuke/Downloads/xpack-qemu-arm-8.2.2-1/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin" /home/daisuke/svn_/qemu/linux/buildroot-2024.02.3/support/scripts/mkusers /home/daisuke/svn_/qemu/linux/buildroot-2024.02.3/output/build/buildroot-fs/full_users_table.txt /home/daisuke/svn_/qemu/linux/buildroot-2024.02.3/output/build/buildroot-fs/ext2/target >> /home/daisuke/svn_/qemu/linux/buildroot-2024.02.3/output/build/buildroot-fs/ext2/fakeroot echo "/home/daisuke/svn_/qemu/linux/buildroot-2024.02.3/output/host/bin/makedevs -d /home/daisuke/svn_/qemu/linux/buildroot-2024.02.3/output/build/buildroot-fs/full_devices_table.txt /home/daisuke/svn_/qemu/linux/buildroot-2024.02.3/output/build/buildroot-fs/ext2/target" >> /home/daisuke/svn_/qemu/linux/buildroot-2024.02.3/output/build/buildroot-fs/ext2/fakeroot printf ' rm -rf /home/daisuke/svn_/qemu/linux/buildroot-2024.02.3/output/build/buildroot-fs/ext2/target/usr/lib/udev/hwdb.d/ /home/daisuke/svn_/qemu/linux/buildroot-2024.02.3/output/build/buildroot-fs/ext2/target/etc/udev/hwdb.d/\n' >> /home/daisuke/svn_/qemu/linux/buildroot-2024.02.3/output/build/buildroot-fs/ext2/fakeroot echo "find /home/daisuke/svn_/qemu/linux/buildroot-2024.02.3/output/build/buildroot-fs/ext2/target/run/ -mindepth 1 -prune -print0 | xargs -0r rm -rf --" >> /home/daisuke/svn_/qemu/linux/buildroot-2024.02.3/output/build/buildroot-fs/ext2/fakeroot echo "find /home/daisuke/svn_/qemu/linux/buildroot-2024.02.3/output/build/buildroot-fs/ext2/target/tmp/ -mindepth 1 -prune -print0 | xargs -0r rm -rf --" >> /home/daisuke/svn_/qemu/linux/buildroot-2024.02.3/output/build/buildroot-fs/ext2/fakeroot printf ' \n' >> /home/daisuke/svn_/qemu/linux/buildroot-2024.02.3/output/build/buildroot-fs/ext2/fakeroot printf ' \n' >> /home/daisuke/svn_/qemu/linux/buildroot-2024.02.3/output/build/buildroot-fs/ext2/fakeroot printf ' rm -f /home/daisuke/svn_/qemu/linux/buildroot-2024.02.3/output/images/rootfs.ext2\n /home/daisuke/svn_/qemu/linux/buildroot-2024.02.3/output/host/sbin/mkfs.ext2 -d /home/daisuke/svn_/qemu/linux/buildroot-2024.02.3/output/build/buildroot-fs/ext2/target -r 1 -N 0 -m 5 -L "rootfs" -I 256 -O ^64bit /home/daisuke/svn_/qemu/linux/buildroot-2024.02.3/output/images/rootfs.ext2 "64M" || { ret=$?; echo "*** Maybe you need to increase the filesystem size (BR2_TARGET_ROOTFS_EXT2_SIZE)" 1>&2; exit $ret; }\n' >> /home/daisuke/svn_/qemu/linux/buildroot-2024.02.3/output/build/buildroot-fs/ext2/fakeroot chmod a+x /home/daisuke/svn_/qemu/linux/buildroot-2024.02.3/output/build/buildroot-fs/ext2/fakeroot PATH="/home/daisuke/svn_/qemu/linux/buildroot-2024.02.3/output/host/bin:/home/daisuke/svn_/qemu/linux/buildroot-2024.02.3/output/host/sbin:/home/daisuke/.nvm/versions/node/v20.13.1/bin:/home/daisuke/Downloads/xpack-arm-none-eabi-gcc-13.2.1-1.1/bin:/home/daisuke/Downloads/xpack-qemu-arm-8.2.2-1/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin" FAKEROOTDONTTRYCHOWN=1 /home/daisuke/svn_/qemu/linux/buildroot-2024.02.3/output/host/bin/fakeroot -- /home/daisuke/svn_/qemu/linux/buildroot-2024.02.3/output/build/buildroot-fs/ext2/fakeroot rootdir=/home/daisuke/svn_/qemu/linux/buildroot-2024.02.3/output/build/buildroot-fs/ext2/target table='/home/daisuke/svn_/qemu/linux/buildroot-2024.02.3/output/build/buildroot-fs/full_devices_table.txt' mke2fs 1.47.0 (5-Feb-2023) Creating regular file /home/daisuke/svn_/qemu/linux/buildroot-2024.02.3/output/images/rootfs.ext2 Creating filesystem with 65536 1k blocks and 16384 inodes Filesystem UUID: 5ef0e39c-49e5-42f0-9d1f-2fc756b89405 Superblock backups stored on blocks: 8193, 24577, 40961, 57345
ちょっと分かりにくいですが、output/target と output/build/buildroot-fs/ext2 あたりに見えます。
しかし、今見てみると、後者は fakeroot というファイルが1つあるだけですので、前者がルートファイルシステムっぽいです。
おわりに
今回は、前回 起動した、QEMU の組み込み Linux について、補足をしました。
次回こそは、u-boot の組み込みなど、やってみたいと思います。
最後になりましたが、エンジニアグループのランキングに参加中です。
気楽にポチッとよろしくお願いいたします🙇
今回は以上です!
最後までお読みいただき、ありがとうございました。