ラズパイ3B とラズパイ3B+ が止まったままで、何かに使えないかと思いつつ、 ディスクアクセスが遅いので、 SD カードを read-only で使う用途はどうかと思っています。 そこで、実機で試す前に Raspberry Pi OS を qemu で動かして read-only の挙動を確認することにしました。
動作確認バージョン
- qemu 9.2.2
- Raspberry Pi OS (64-bit)
- Raspberry Pi OS Lite
- Release date: November 19th 2024
- Kernel version: 6.6
- Debian version: 12 (bookworm)
- Size: 438MB
ダウンロード
「Raspberry Pi OS」で検索して、 https://www.raspberrypi.com/software/ から「See all download options」と辿って https://www.raspberrypi.com/software/operating-systems/ に一覧があったので、そこから 64-bit の Raspberry Pi OS Lite をダウンロードしました。
カーネルなどを取り出し
Linux 上では頑張ってループバックマウントして取り出す方法もありますが、 macOS でも使える方法として、 p7zip
でディスクイメージファイルをアーカイブファイルとして扱って取り出しました。
unxz 2024-11-19-raspios-bookworm-arm64-lite.img.xz
7z l 2024-11-19-raspios-bookworm-arm64-lite.img
7z x 2024-11-19-raspios-bookworm-arm64-lite.img 0.fat
7z l 0.fat
7z x 0.fat bcm2710-rpi-3-b.dtb cmdline.txt config.txt kernel8.img initramfs8
パーティションが 0.fat
と 1.img
というファイルとして見えるので、 起動に使われる 0.fat
の方を取り出して、 さらにその中からカーネルなどを取り出しました。
ディスクの拡張
qemu-img create -b 2024-11-19-raspios-bookworm-arm64-lite.img -F raw -f qcow2 diff.qcow2 8G
で差分ディスクを作成しても良かったのですが、 p7zip
でのファイル取り出しが難しくなるので、 コピーしてリサイズすることにしました。
cp 2024-11-19-raspios-bookworm-arm64-lite.img disk.img
qemu-img resize disk.img 8G
リサイズ後は 8G の SDHC カードに書き込んだ状態に相当すると思います。
初回起動
cmdline.txt
の内容を確認すると init=
が firstboot
になっていて、 初回起動用の特別処理がありそうとわかります。
% cat cmdline.txt
console=serial0,115200 console=tty1 root=PARTUUID=8a438930-02 rootfstype=ext4 fsck.repair=yes rootwait quiet init=/usr/lib/raspberrypi-sys-mods/firstboot
cmdline.txt
の内容を使って初回起動します。
PARTUUID
は変化に合わせて指定するのは大変なのと、 qemu
の引数でデバイスは固定なので、 root=/dev/mmcblk0p2
に書き換えて使います。
その他のオプションは、 Raspberry Pi OS 64-bit を qemu 7.2.0 で動作させる | hiroの長い長い冒険日記 の qemu のオプションについて などを参考にしています。
qemu-system-aarch64 -m 1024 -M raspi3b -kernel kernel8.img -initrd initramfs8 -dtb bcm2710-rpi-3-b.dtb -drive file=disk.img,format=raw -append "console=serial0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 fsck.repair=yes rootwait quiet init=/usr/lib/raspberrypi-sys-mods/firstboot" -serial stdio -no-reboot -device usb-kbd -device usb-tablet -device usb-net,netdev=net0 -netdev user,id=net0,hostfwd=tcp::2222-:22
パーティションのリサイズと SSH ホスト鍵の自動生成などが実行されていました。
通常の起動
初回起動前と同様にファイルを取り出すと、 PARTUUID
が変化して、 quiet
と init=
の指定が削除されていました。
% cat cmdline.txt
console=serial0,115200 console=tty1 root=PARTUUID=071b9753-02 rootfstype=ext4 fsck.repair=yes rootwait
初回起動と同様に root=
の指定は変更しています。
コンソールのサイズを変更するために bcm2708_fb.fbwidth=1280 bcm2708_fb.fbheight=768
を追加しました。
qemu-system-aarch64 -m 1024 -M raspi3b -kernel kernel8.img -initrd initramfs8 -dtb bcm2710-rpi-3-b.dtb -drive file=disk.img,format=raw -append "console=serial0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 fsck.repair=yes rootwait bcm2708_fb.fbwidth=1280 bcm2708_fb.fbheight=768" -serial stdio -no-reboot -device usb-kbd -device usb-tablet -device usb-net,netdev=net0 -netdev user,id=net0,hostfwd=tcp::2222-:22
-no-reboot
を指定しているので、 自動で再起動するときに終了します。
2回目の起動
通常起動の初回(全体の2回目の起動)は、 キーボードの設定とユーザーの作成がありました。 昔の Raspbian で最初から作成されていた pi
ユーザーは存在しないようです。
ssh 接続
sudo raspi-config
で 3 Interface Options
の I1 SSH
で有効にすると ssh -p 2222 ${作成したユーザー}@localhost
や ssh -p 2222 -l ${作成したユーザー} localhost
で接続できるようになります。
read only 化
sudo raspi-config
で 4 Performance Options
の P2 Overlay File System
で overlay file system を Yes にすると overlayroot
パッケージが追加インストールされて initramfs
(/boot/firmware
の initramfs8
と initramfs_2712
) が更新されて、 cmdline.txt
の先頭に overlayroot=tmpfs
が追加されていました。
initramfs8
が更新されているので、 p7zip
で取り出して、 それに合わせて qemu-system-aarch64 -m 1024 -M raspi3b -kernel kernel8.img -initrd initramfs8 -dtb bcm2710-rpi-3-b.dtb -drive file=disk.img,format=raw -append "overlayroot=tmpfs console=serial0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 fsck.repair=yes rootwait bcm2708_fb.fbwidth=1280 bcm2708_fb.fbheight=768" -serial stdio -no-reboot -device usb-kbd -device usb-tablet -device usb-net,netdev=net0 -netdev user,id=net0,hostfwd=tcp::2222-:22
のように overlayroot=tmpfs
を追加して起動して、 df
などで確認すると /
が overlayroot
になっていました。
boot partition の write-protected を Yes にすると、 /etc/fstab
の /boot/firmware
の行の defaults
が defaults,ro
に変わっていました。
/
の overlay 化と boot partition の write-protected は独立して設定できましたが、 overlay を Yes にして起動している状態だと、 /etc/fstab
の書き換えが再起動時に反映できないので、 boot partition の write-protected は変更できませんでした。 そのため、一気に両方有効にした状態から戻すには、 overlay を No にして再起動した後、 boot partition の write-protected を No にする必要がありました。
まとめ
qemu
で raspi3b
の動作確認ができました。
そして overlayroot
などの read-only にする仕組みも確認できました。
overlayrootでUbuntuを一時的に読み込み専用にする によると overlayroot
はもっと色々な機能があるようなので、 変更は USB マスストレージに保存するようにして SD カードは読み込み専用のまま書き込み内容も保存する、ということもできそうです。