土日の勉強ノート

AI、機械学習、最適化、Pythonなどについて、技術調査、技術書の理解した内容、ソフトウェア/ツール作成について書いていきます

QEMUで組み込みLinux(Buildroot+virtボード)で ARM64bitを起動する

前回 は、QEMU で Arm の組み込み Linux(Buildroot+BusyBox+U-Boot)で、initramfs を追加しました。

これまで、今回は、initramfsを追加していきます。

それでは、やっていきます。

はじめに

「QEMUを動かす」の記事一覧です。良かったら参考にしてください。

QEMUを動かすの記事一覧
・第1回:STM32(ARM Cortex-M)を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)をやってみる、の補足
・第19回:QEMUで組み込みLinux(Buildroot+BusyBox)にU-Bootを追加する
・第20回:QEMUで組み込みLinux(Buildroot+BusyBox+U-Boot)で起動する
・第21回:QEMUで組み込みLinux(Buildroot+BusyBox+U-Boot)をinitramfsで起動する
・第22回:QEMUで組み込みLinux(Buildroot+virtボード)で ARM64bitを起動する ← 今回

以下は、Buildroot の Documentation のリンクです。

https://buildroot.org/downloads/manual/manual.html

ここで使用する環境は、VirtualBox に入れた Ubuntu 22.04 です。

Buildroot を使います。Buildroot に含まれている U-Boot と、QEMU を使います。

これまで進めてきた各環境については以下の通りです。

ツール 設定値
Buildroot qemu_arm_vexpress_defconfig
U-Boot vexpress_ca9x4
QEMU vexpress-a9

これまで使ってきた vexpress とは、Arm 社の Versatile Express という開発ボードをターゲットとしたものでした。

今回からは、QEMU が仮想環境用として提供している virt という開発ボード(実際には存在しないのでプラットフォームの方が適切?)に変更します。

今後は、QEMU 環境で、ネットワークも使っていきたいので、ターゲットも仮想環境を想定したものが都合が良さそうということで、変更することにしました。

また、ARM 32bit にしようと思ったのですが、Buildroot のコンフィグを virt で検索すると、ARM 64bit しかありませんでした。アドレスが長いので少し気が進みません(笑)。

各ツールの設定値については以下のように変更になります。

ツール 設定値
Buildroot qemu_aarch64_virt_defconfig
U-Boot qemu_arm64_defconfig
QEMU virt(virt-8.2)

それでは、やっていきます。

Buildrootのビルド

Buildroot については、https://daisuke20240310.hatenablog.com/entry/buildroot で準備したものと同じもの(buildroot-2024.02.3.tar.gz)を使用します。

解凍して、defconfig を検索します。

$ tar zxvf buildroot-2024.02.3.tar.gz
$ cd buildroot-2024.02.3/

$ find . -name '*defconfig' | grep virt
./configs/qemu_riscv64_virt_efi_defconfig
./configs/qemu_riscv64_virt_defconfig
./configs/qemu_riscv64_nommu_virt_defconfig
./configs/qemu_riscv32_virt_defconfig
./configs/qemu_aarch64_virt_defconfig

冒頭で言ったように、Arm 32bit の virt 用のコンフィグがありませんでした。仕方ないので、Arm 64bit を使います。

Buildroot はクロスコンパイラを自動で準備してくれるため、環境変数の設定などが無くてもビルドできます。

また、Buildroot は並列コンパイルをサポートしていないので、-j を付けても意味がありません。

$ make qemu_aarch64_virt_defconfig
#
# configuration written to /home/daisuke/svn_/qemu/linux2/buildroot-2024.02.3/.config
#

$ make 2>&1 | tee 20240713-make.log

1時間程度で完了しました。

Buildrootを起動する

早速、起動していきます。

$ cd output/images/
$ ./start-qemu.sh
Booting Linux on physical CPU 0x0000000000 [0x410fd034]
Linux version 6.1.44 (daisuke@daisuke-VirtualBox) (aarch64-buildroot-linux-gnu-gcc.br_real (Buildroot 2024.02.3) 12.3.0, GNU ld (GNU Binutils) 2.40) #1 SMP Sat Jul 13 18:28:57 JST 2024
random: crng init done
Machine model: linux,dummy-virt
efi: UEFI not found.
Zone ranges:
  DMA      [mem 0x0000000040000000-0x0000000047ffffff]
  DMA32    empty
  Normal   empty
Movable zone start for each node
Early memory node ranges
  node   0: [mem 0x0000000040000000-0x0000000047ffffff]
Initmem setup node 0 [mem 0x0000000040000000-0x0000000047ffffff]
(省略)
OK

Welcome to Buildroot
buildroot login:

無事に起動しました。

ユーザ名は root で、パスワードはありません。シャットダウンは BusyBox の poweroff を使います。

buildroot login: root
# poweroff
# Stopping network: OK
Stopping klogd: OK
Stopping syslogd: OK
Seeding 256 bits and crediting
Saving 256 bits of creditable seed for next boot
umount: devtmpfs busy - remounted read-only
EXT4-fs (vda): re-mounted. Quota mode: disabled.
The system is going down NOW!
Sent SIGTERM to all processes
Sent SIGKILL to all processes
Requesting system poweroff
reboot: Power down

start-qemu.shを確認する

以前も start-qemu.sh を確認しました。同じだと思いますが、一応見ておきます。

最後の1行は見にくいので改行を入れています。

$ cat 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=''
fi

if ! ${mode_sys_qemu}; then
    export PATH="/home/daisuke/svn_/qemu/linux2/buildroot-2024.02.3/output/host/bin:${PATH}"
fi

exec qemu-system-aarch64 -M virt -cpu cortex-a53 -nographic -smp 1 ¥
  -kernel Image \
  -append "rootwait root=/dev/vda console=ttyAMA0" \
  -netdev user,id=eth0 \
  -device virtio-net-device,netdev=eth0 \
  -drive file=rootfs.ext4,if=none,format=raw,id=hd0 \
  -device virtio-blk-device,drive=hd0 \
  ${EXTRA_ARGS} "$@"

カーネルのファイル名が zImage から Image になりました。あと、ルートファイルシステムが、ext2 から ext4 になりました。

QEMU の起動パラメータを改めて見てみます。

以下の2行は、ネットワークのインタフェースの定義です。

-netdev user,id=eth0 \
-device virtio-net-device,netdev=eth0 \

また、以下の2行は、ルートファイルシステムをマウントするためのパラメータです。

-drive file=rootfs.ext4,if=none,format=raw,id=hd0 \
-device virtio-blk-device,drive=hd0 \

Buildrootを起動してネットワークを確認する

では、再度、Buildroot を起動します。

ネットワークを確認していきます。

まず、インタフェースを確認します。

IPアドレスは、10.0.2.15 です。VirtualBox の Ubuntu 22.04 と同じ IP アドレスですが、たまたまでしょうか。

# ifconfig
eth0      Link encap:Ethernet  HWaddr 52:54:00:12:34:56
          inet addr:10.0.2.15  Bcast:10.0.2.255  Mask:255.255.255.0
          inet6 addr: fec0::5054:ff:fe12:3456/64 Scope:Site
          inet6 addr: fe80::5054:ff:fe12:3456/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:3 errors:0 dropped:0 overruns:0 frame:0
          TX packets:9 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:1290 (1.2 KiB)  TX bytes:1291 (1.2 KiB)

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

その他の情報を見ます。

# cat /etc/resolv.conf
nameserver 10.0.2.3 # eth0

# route
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
default         _gateway        0.0.0.0         UG    0      0        0 eth0
10.0.2.0        *               255.255.255.0   U     0      0        0 eth0

なるほど、続いて、ping を実行してみます。

# ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8): 56 data bytes
64 bytes from 8.8.8.8: seq=0 ttl=255 time=11.690 ms
64 bytes from 8.8.8.8: seq=1 ttl=255 time=7.859 ms
^C

# ping google.co.jp
PING google.co.jp (172.217.175.227): 56 data bytes
64 bytes from 172.217.175.227: seq=0 ttl=255 time=13.967 ms
64 bytes from 172.217.175.227: seq=1 ttl=255 time=15.197 ms
^C

繋がりました。インターネットに繋がっているようです。

また、10.0.2.2、10.0.0.3 は、反応がありました。

続いて、wget を試してみます。

# wget https://daisuke20240310.hatenablog.com/entry/initramfs
wget: not an http or ftp url: https://daisuke20240310.hatenablog.com/entry/initramfs

調べてみると、BusyBox の wget は SSL をサポートしてないとのことです。

# wget http://www.google.co.jp
Connecting to www.google.co.jp (142.250.199.99:80)
saving to 'index.html'
index.html           100% |********************************| 20468  0:00:00 ETA
'index.html' saved

# ls
index.html

Google のトップページの index.html は取得することが出来ました。

今回は以上です。

おわりに

今回は、virt ボードを使って、ARM 64bit の Buildroot を動かしました。

この環境で何ができるかをもう少し調査してみます。

最後になりましたが、エンジニアグループのランキングに参加中です。

気楽にポチッとよろしくお願いいたします🙇

今回は以上です!

最後までお読みいただき、ありがとうございました。