スポンサーリンク

Raspberry Pi OS 32-bit を qemu 7.2.0 で起動する

Very_Beautiful_woods_landscape
記事内に広告が含まれています。
スポンサーリンク

QEMU 仮想マシンで 32-bit Raspberry Pi OS を試す

先日、64-bit 版の Raspberry Pi OS を qemu 7.2.0 仮想マシン (raspi3b) で起動してみました。

GUI 版だと反応も鈍く常用するには難しい感触でしたが、CUI 版の Lite であれば 40秒前後でログインプロンプトが表示され、入力への反応もまずまずでしたので、試用する環境として使えるレベルではないかと感じました。

これまでは qemu-system-aarch64 の環境で 64-bit 版を試してきましたが、32-bit 版を使用した時にもっと軽く動作するのではないか、また 32-bit 版の環境がどの位実用的に使えるかどうかを確認する為に、qemu 7.2.0 で 32-bit 版の Raspberry Pi OS を起動させて試してみました。

スポンサーリンク

動作環境 : WSL2 Ubuntu 23.04 + qemu 7.2.0

動作環境として WSL2 Ubuntu 23.04 上で qemu 7.2.0 を使用しました。ARM CPU をエミュレートする qemu は qemu-system-arm (32-bit) と qemu-system-aarch64 (64-bit) の二種類です。それぞれの対応する Raspberry Pi の種類は以下の通りです。

$ qemu-system-arm --version
QEMU emulator version 7.2.0 (Debian 1:7.2+dfsg-5ubuntu2)
Copyright (c) 2003-2022 Fabrice Bellard and the QEMU Project developers

$ qemu-system-arm -machine help | grep -i rasp
raspi0               Raspberry Pi Zero (revision 1.2)
raspi1ap             Raspberry Pi A+ (revision 1.1)
raspi2b              Raspberry Pi 2B (revision 1.1)

$ qemu-system-aarch64 --version
QEMU emulator version 7.2.0 (Debian 1:7.2+dfsg-5ubuntu2)
Copyright (c) 2003-2022 Fabrice Bellard and the QEMU Project developers

$ qemu-system-aarch64 -machine help | grep -i raspi
raspi0               Raspberry Pi Zero (revision 1.2)
raspi1ap             Raspberry Pi A+ (revision 1.1)
raspi2b              Raspberry Pi 2B (revision 1.1)
raspi3ap             Raspberry Pi 3A+ (revision 1.0)
raspi3b              Raspberry Pi 3B (revision 1.2)

32-bit 版の qemu-system-arm では raspi2b まで、64-bit 版の qemu-system-aarch64 では raspi3B まで対応しています。

Lite のイメージに含まれる kernel と dtb の種類

64-bit の Raspberry Pi OS を試した際に、OS のイメージから kernel と dtb ファイルを抜き出しました。

同様にして、32-bit の Raspberry Pi OS からも kernel と dtb ファイルを抜き出します。手順は上記と同様ですので省略しますが、Lite イメージには複数の kernel と dtb が含まれていました。

$ ls kernel*
kernel.img
kernel7.img
kernel7l.img
kernel8.img

$ ls *dtb
bcm2708-rpi-b-plus.dtb
bcm2708-rpi-b-rev1.dtb
bcm2708-rpi-b.dtb
bcm2708-rpi-cm.dtb
bcm2708-rpi-zero-w.dtb
bcm2708-rpi-zero.dtb
bcm2709-rpi-2-b.dtb
bcm2709-rpi-cm2.dtb
bcm2710-rpi-2-b.dtb
bcm2710-rpi-3-b-plus.dtb
bcm2710-rpi-3-b.dtb
bcm2710-rpi-cm3.dtb
bcm2710-rpi-zero-2-w.dtb
bcm2710-rpi-zero-2.dtb
bcm2711-rpi-4-b.dtb
bcm2711-rpi-400.dtb
bcm2711-rpi-cm4.dtb
bcm2711-rpi-cm4s.dtb

kernel については、Raspberry Pi 公式に説明がありました。

  • kernel.img ... 32-bit (For Raspberry Pi 1, Zero and Zero W, and Raspberry Pi Compute Module 1)
  • kernel7.img ... 32-bit (For Raspberry Pi 2, 3, 3+ and Zero 2 W, and Raspberry Pi Compute Modules 3 and 3+)
  • kernel7l.img ... 32-bit (For Raspberry Pi 4 and 400, and Raspberry Pi Compute Module 4)
  • kernel8.img ... 64-bit (For Raspberry Pi 3, 3+, 4, 400 and Zero 2 W, and Raspberry Pi Compute Modules 3, 3+ and 4)

qemu では Raspberry Pi 4 のエミュレーションはできませんので kernel7l.img は使用せず、

  • 32-bit の場合は kenrel.img か kernel7.img
  • 64-bit の場合は kernel8.img

を使用します。

また、dtb ファイルは、ファイル名に機種が書かれていますので、

  • Raspberry Pi 2B には bcm2709-rpi-2-b.dtb か bcm2710-rpi-2-b.dtb
  • Raspberry Pi 3B には bcm2710-rpi-3-b.dtb

を使用します。これらの組み合わせで、qemu で正常に起動するかどうかを確認します。

32-bit Raspberry Pi OS Lite を raspi2b で動作させる

Raspberry Pi 2B をエミュレートする raspi2b は、qemu-system-arm と qemu-system-aarch64 の両方で選択できます。

そこで、32-bit Raspberry Pi OS を両方の環境で起動させてみました。起動スクリプトは以下のようになります。

$ cat run_raspi2_lite_arm.sh
#!/bin/sh

qemu-system-arm \
-m 1024 \
-M raspi2b \
-kernel kernel7.img \
-dtb bcm2709-rpi-2-b.dtb \
-drive format=raw,file=2023-02-21-raspios-bullseye-armhf-lite.img \
-append "console=ttyAMA0 root=/dev/mmcblk0p2 rw rootwait rootfstype=ext4 dwc_otg.fiq_fsm_enable=0 bcm2708_fb.fbwidth=640 bcm2708_fb.fbheight=480" \
-serial stdio \
-no-reboot \
-device usb-kbd \
-device usb-tablet \
-device usb-net,netdev=net0 \
-netdev user,id=net0,hostfwd=tcp::2222-:22

qemu-system-arm を qemu-system-aarch64 に書き換えると、64-bit 用のエミュレータ環境で 32-bit で動作する kernel を起動させる事になります。

dtb は bcm2709 が使用できます。bcm2710 では起動できませんでした。(おそらく bcm2710 は 64-bit 用の dtb だと思います)

qemu-system-arm で起動した場合

qemu-system-arm -machine raspi2 で起動した 32-bit Raspberry Pi OS Lite です。

qemu-system-arm raspi2 で起動した 32-bit Raspberry Pi OS

uname -m と arch の結果は共に armv7l、getconf LONG_BIT の結果は 32、/bin/bash は ARM の EFL 32-bit バイナリで、link されている library も armhf です。kernel、ライブラリ、実行ファイル共に 32-bit で起動している事が分かります。

qemu-system-aarch64 で起動した場合

qemu-system-aarch64 -machine raspi2 で起動した 32-bit Raspberry Pi OS Lite です。見た目の差はありません。(起動スクリプトは別になっています)

qemu-system-aarch64 raspi2 で起動した 32-bit Raspberry Pi OS

qemu-system-aarch64 で起動していますが、uname -m、arch、getconf LONG_BIT、file /bin/bash の結果は全て qemu-system-arm と同じでした。

起動に要した時間

qemu-system-arm と qemu-system-aarch64 について、32-bit Raspberry Pi OS を qemu で起動させてから login プロンプトが表示されるまでの時間を測定しました。

qemu-system-起動時間
arm5 分 42 秒
aarch646 分 23 秒
login プロンプトが表示されるまでの時間
(WSL2 Ubuntu 23.04)

rasp3b で 64-bit で動作させている時 (lite で40秒前後) と比較すると、かなり時間を要しています。また、arm よりも aarch64 で起動した方が30秒以上長い時間が掛かっています。

起動時の気になる箇所

32-bit Raspberry Pi OS を WSL2 Ubuntu 23.04 の qemu で raspi2 で起動させている際に、幾つか気になる事がありました。

  • 起動途中で一旦引っ掛かる箇所があります。emergency mode になっているようです。Enter を押すと起動が継続し、最終的には login プロンプトが表示されます。
You are in emergency mode. After logging in, type "journalctl -xb" to view
system logs, "systemctl reboot" to reboot, "systemctl default" or "exit"
to boot into default mode.

Cannot open access to console, the root account is locked.
See sulogin(8) man page for more details.

Press Enter to continue.
  • journalctl -xb で状況を確認すると、認識できていない機器や CPU の例外が発生していました。抜粋して以下に記載します。特に NMI backtrace は起動中に13回発生していましたので、起動に時間を要している原因はこの辺りにありそうです。
raspberrypi kernel: cpu cpu0: Cannot get clock for CPU0
raspberrypi kernel: raspberrypi-cpufreq: probe of raspberrypi-cpufreq failed with error -2

raspberrypi kernel: bcm2835_vchiq 3f00b840.mailbox: failed to set channelbase

raspberrypi kernel: bcm2835-power bcm2835-power: ASB register ID returned 0x00000000
raspberrypi kernel: bcm2835_thermal 3f212000.thermal: Not able to read trip_temp: -33
raspberrypi kernel: bcm2835-clk 3f101000.cprman: tsens: couldn't lock PLL
raspberrypi kernel: bcm2835_thermal: probe of 3f212000.thermal failed with error -33

raspberrypi kernel: rcu: INFO: rcu_sched self-detected stall on CPU
raspberrypi kernel: rcu:         3-....: (2060 ticks this GP) idle=d97/1/0x40000002 softirq=81/81 fqs=7>
raspberrypi kernel:         (t=2100 jiffies g=-1023 q=3501)
raspberrypi kernel: rcu: rcu_sched kthread starved for 274 jiffies! g-1023 f0x0 RCU_GP_WAIT_FQS(5) ->st>
raspberrypi kernel: rcu:         Unless rcu_sched kthread gets sufficient CPU time, OOM is now expected>
raspberrypi kernel: rcu: RCU grace-period kthread stack dump:
raspberrypi kernel: task:rcu_sched       state:R  running task     stack:    0 pid:   14 ppid:     2 fl>
raspberrypi kernel: Backtrace:

raspberrypi kernel: NMI backtrace for cpu 1
raspberrypi kernel: CPU: 1 PID: 18 Comm: migration/1 Not tainted 5.15.84-v7+ #1613
raspberrypi kernel: Hardware name: BCM2835
raspberrypi kernel: Stopper: multi_cpu_stop+0x0/0x170 <- stop_machine_cpuslocked+0x108/0x184
raspberrypi kernel: PC is at multi_cpu_stop+0xf8/0x170
raspberrypi kernel: LR is at rcu_momentary_dyntick_idle+0x24/0x64
raspberrypi kernel: pc : [<801e9518>]    lr : [<8019c944>]    psr: 20000013
raspberrypi kernel: sp : 8156bed8  ip : 8156bec8  fp : 8156bf0c
raspberrypi kernel: r10: 00000000  r9 : a0000013  r8 : 00000001
raspberrypi kernel: r7 : 81005058  r6 : 00000001  r5 : 81553dcc  r4 : 81553de0
raspberrypi kernel: r3 : b772c854  r2 : 00000002  r1 : 00000000  r0 : 0063f833
raspberrypi kernel: Flags: nzCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment user
raspberrypi kernel: Control: 10c5387d  Table: 0252006a  DAC: 00000055
raspberrypi kernel: CPU: 1 PID: 18 Comm: migration/1 Not tainted 5.15.84-v7+ #1613
raspberrypi kernel: Hardware name: BCM2835
raspberrypi kernel: Stopper: multi_cpu_stop+0x0/0x170 <- stop_machine_cpuslocked+0x108/0x184
raspberrypi kernel: Backtrace:

あまりにも時間を要しているのは変ですので、別の環境で試してみました。

動作環境 : Windows11 + qemu 7.2.0 で検証

Windows11 版の qemu 7.2.0 で試したところ、起動時間を大きく短縮できました。emergency mode に落ちる事もなく、backtrace も発生しませんでした。WSL2 Ubuntu 23.04 の qemu 7.2.0 の結果と比較すると下の表のようになります。

qemu-system-起動時間
Windows11
起動時間
WSL2 Ubuntu
arm1 分 18 秒5 分 42 秒
aarch641 分 17 秒6 分 23 秒
login プロンプトが表示されるまでの時間
(Windows11)

起動スクリプトは以下の通りです。

>type run_raspi2_lite_arm.bat

"C:\Program Files\qemu\qemu-system-arm.exe" ^
-m 1024 ^
-M raspi2b ^
-kernel kernel7.img ^
-dtb bcm2709-rpi-2-b.dtb ^
-drive format=raw,file=2023-02-21-raspios-bullseye-armhf-lite.img ^
-append "console=ttyAMA0 root=/dev/mmcblk0p2 rw rootwait rootfstype=ext4 dwc_otg.fiq_fsm_enable=0 bcm2708_fb.fbwidth=640 bcm2708_fb.fbheight=480" ^
-serial stdio ^
-no-reboot ^
-device usb-kbd ^
-device usb-tablet ^
-device usb-net,netdev=net0 ^
-netdev user,id=net0,hostfwd=tcp::2222-:22

同じ 32-bit Lite のイメージ、及び 32-bit Lite のイメージから取り出した kernel7.img と bcm2709-rpi-2-b.dtb を使用した場合でも、Windows11 の qemu で起動すると WSL2 Ubuntu 23.04 qemu の 20%程度の約 80 秒で起動できました。

64-bit の場合より若干遅いですが、この程度の時間で起動するのであれば検証には十分です。起動してからの CUI の反応も許容できる程度でした。

32-bit Raspberry Pi OS を raspi3b で動作させる

以下、WSL2 Ubuntu 23.04 と Windows11 の qemu 7.2.0 で検証しています。

raspi3b は qemu-system-aarch64 でのみ選択できます。

残念ながら 32-bit の kernel7.img では raspi3b は起動させる事ができませんでした。ラズベリーも表示されず、起動メッセージも表示されません。

64-bit の kernel8.img と bcm2710-rpi-3-b.dtb の組み合わせで起動する事ができました。起動に要した時間は 42 ~ 43 秒でしたので 64-bit の時と変わりません。

qemu-system-aarch64 raspi3 で起動した 32-bit Raspberry Pi OS

kernel のアーキテクチャを調べると、uname -m も arch も aarch64 を返しますので、kernel は 64-bit で動作していると思います。ただ、getconf LONG_BIT は32を返し、ライブラリや実行ファイルは 32-bit なので、実行環境は 32-bit で動作していると思います。

簡単なプログラムを作って確認してみました。

hiro@raspberrypi:~ $ cat test.c
#include <stdio.h>

int main ( void )
{
  printf("Hello World\n");
}
hiro@raspberrypi:~ $ gcc -o test test.c
hiro@raspberrypi:~ $ ./test
Hello World
hiro@raspberrypi:~ $ file ./test
./test: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, BuildID[sha1]=f2fbd35c5553e86caee0d4e3c40b0fc306fdaecf, for GNU/Linux 3.2.0, not stripped
hiro@raspberrypi:~ $ ldd ./test
        /usr/lib/arm-linux-gnueabihf/libarmmem-${PLATFORM}.so => /usr/lib/arm-linux-gnueabihf/libarmmem-v8l.so (0xf7dab000)
        libc.so.6 => /lib/arm-linux-gnueabihf/libc.so.6 (0xf7c57000)
        /lib/ld-linux-armhf.so.3 (0xf7dc0000)

出来たバイナリは 32-bit で、リンクされるライブラリも 32-bit のものです。kernel は 64-bit で動作していても、実行環境は 32-bit で動作している事が分かります。

まとめ

Raspberry Pi OS 32-bit を qemu 7.2.0 で起動させてみました。raspi2b と raspi3b を使用しました。他にも、raspi0 (Raspberry Pi Zero) も起動させようとしましたが、ラズベリー1個は表示されるものの途中でフリーズしたようになり断念しました。

  • 32-bit の Raspberry Pi OS の kernel を起動させる場合には、同じ qemu 7.2.0 でも、WSL2 Ubuntu 23.04 よりも Windows11 版の方が早く起動できました。CUI の Lite 版であれば約 80 秒でログインプロンプトが表示されます。WSL2 Ubuntu の場合は 5 ~ 6 分を要しました。原因は分かりませんが、現状では Windows11 版の qemu で実行するのが良いかと思います。
  • 64-bit 版と比較して、32-bit 版の Raspberry Pi OS raspi2b の起動に要する時間は 80 秒程度になります。raspi3b を使用すると 64-bit と変わらず 40 秒程度になります。
    • raspi2b を使用すると、kernel から実行環境も含めて全て 32-bit の環境になります。
    • raspi3b を使用すると、kernel は 64-bit、実行環境は 32-bit の環境になります。簡単なプログラムを作成して実行ファイルを確認しましたが、32-bit で動作していました。

以上から、32-bit ARM 向けのバイナリを作成・実行する環境としては、

  • Windows11 版の qemu 7.2.0 を使用し、少し遅くても良いのであれば raspi2b
  • 再起動を繰り返すような用途、或いは WSL2 で qemu 7.2.0 を使用したい場合には、kernel が 64-bit でもよい場合には raspi3b

という使い分けになるかと思います。

今回のアイキャッチ画像

森の中の風景を生成しました。倒木が雰囲気を出しています。

コメント

タイトルとURLをコピーしました