概要
RISC-V の VM イメージを作って、QEMU で動かしてみた。特にそれを使って何かをしようというわけではないけれど、『RISC-V 原典』を読み進められなかった (2 回目) 腹いせにやってみた。
そんなに大げさなことをやるわけではなく、既に RISC-V 用の stage 3 を作っている方々がおられる (https://wiki.gentoo.org/wiki/Project:RISC-V) ので、ありがたくそれを使ってインストールするのみである。ステップとしては以下のようになる。
- RISC-V の chroot 環境構築
- stage 3 を使用して chroot 環境に Gentoo インストール
- ディスクイメージにまとめて、ブートする
環境は以下のとおり。
- ホスト OS: Gentoo Linux (AMD64)
- app-emulation/qemu-5.1.0-r2
RISC-V stage 3 は 2021 年 1 月現在 RV64GC/lp64d, RV64IMAC/lp64 の 2 種類の命令セット (拡張)/ABI で用意されている。RV64GC が汎用 OS 向けのようなので、RV64GC/lp64d (OpenRC) の環境を作ることにする。
今回作業するにあたり、とても Debian に頼っている。Gentoo 固有でない部分は Debian のガイド (https://wiki.debian.org/RISC-V) をベースにしているし、あとブートローダの部分を自分でうまく構築できなかったので、Debian の U-Boot バイナリを流用している。
chroot 環境構築
Gentoo Wiki の記事 (https://wiki.gentoo.org/wiki/Embedded_Handbook/General/Compiling_with_qemu_user_chroot) を参照しながら RISC-V chroot 環境を作る。
chroot 環境で構築している時はユーザエミュレーション、仮想マシンとしてブートするときにはシステムエミュレーションということで、双方で RV64 エミュレータを作っておく必要がある。勢いで対応しているアーキテクチャは全部有効にした。
# /etc/portage.use/gentoo
app-emulation/qemu static-user QEMU_SOFTMMU_TARGETS: * QEMU_USER_TARGETS: *
emerge. これで RISC-V ELF バイナリを実行できるようになるが、このあとの手順のために、qemu-riscv64
コマンドを指定せずとも透過的に実行できるように (RV64 用の) binfmt_misc の設定をしておく。
# echo ':riscv64:M::\x7f\x45\x4c\x46\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xf3\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-riscv64:' > /proc/sys/fs/binfmt_misc/register
# rc-service qemu-binfmt start
/mnt/gentoo
に stage 3 を展開。chroot 後に RISC-V ELF バイナリを実行するためには、qemu-riscv64
が chroot 環境内で実行できる必要がある。Gentoo Wiki の記事では chroot 環境にもういちど app-emulation/qemu を emerge する手順が書かれているが、どうせ user target は static でコンパイルしてるのだしということで直接 /usr/bin/qemu-riscv64
を chroot 環境にコピーした。
# mkdir /mnt/gentoo
# cd /mnt/gentoo
# wget https://dev.gentoo.org/~dilfridge/stages/stage3-rv64_lp64d-20210109T142246Z.tar.xz # 記事作成時点
# tar xpvf stage3-*.tar.xz --xattrs-include='*.*' --numeric-owner
# cp -a /usr/bin/qemu-riscv64 /mnt/gentoo/usr/bin
これで、AMD64 の Handbook でも見ながら chroot すれば RISC-V 環境ということになる。
# chroot /mnt/gentoo /bin/bash
(chroot) # file /bin/uname
/bin/uname: ELF 64-bit LSB pie executable, UCB RISC-V, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-riscv64-lp64d.so.1, for GNU/Linux 4.15.0, stripped
(chroot) # uname -a
Linux x1e 5.4.80-gentoo-r1 #1 SMP Sun Jan 3 19:36:07 JST 2021 riscv64 GNU/Linux
Gentoo インストール
Handbook (AMD64) を見ながら粛々とインストールを進める。カーネルオプションはデフォルトのままにした。ところで、異なるアークテクチャをエミュレートしているので当然だけれど非常に遅い。カーネルのコンパイルにはこれくらい時間がかかかった (Intel(R) Core(TM) i7-8850H CPU @ 2.60GHz)。
# time make -j6
...
Kernel: arch/riscv/boot/Image.gz is ready
real 51m57.461s
user 299m57.397s
sys 7m7.268s
ほとんど他アーキテクチャと手順は変わらなくて、今回気をつけるのはブートローダ以外はシリアルコンソール (ttyS0
) を開けておくことくらい。普通の TTY および GUI は使えるのかよくわらかないし、自分の場合は使う予定もない。
# /etc/inittab
# SERIAL CONSOLES
s0:12345:respawn:/sbin/agetty -L 9600 ttyS0 vt100
#s1:12345:respawn:/sbin/agetty -L 9600 ttyS1 vt100
ブートローダは、うまく自分で構築することができなかった。選択肢としてはいくつかあって U-Boot がメインの模様。ただ、どうもうまく U-Boot にうまくカーネルを選ばせることができなかった。仕方なしに、Debain の u-boot-qemu パッケージ (https://packages.debian.org/sid/u-boot-qemu) のバイナリをそのまま使うことにした。どうして動くのかよくわからないのだけど、QEMU 実行時にこの U-Boot バイナリを指定すると、/boot/extlinux/extlinux.conf
にもとづいてカーネルを読み込んでくれる。ということで以下が chroot 環境内に作成したファイル。
# /boot/extlinux/extlinux.conf
default 10
menu title U-Boot menu
prompt 0
timeout 50
label 10
menu label Gentoo Linux
linux /boot/vmlinuz-5.10.2-gentoo
append ro root=/dev/vda1
label 10r
menu label Gentoo Linux (recovery mode)
linux /boot/vmlinuz-5.10.2-gentoo
append ro root=/dev/vda1 single
ここまでやって、chroot 環境から抜ける。
ディスクイメージにまとてめてブート
virt-make-fs
コマンド (app-emulation/libguestfs) で chroot ディレクトリをディスクイメージにまとめる。今回なぜか環境変数を手動で渡す必要があった。
$ sudo LIBGUESTFS_PATH=/usr/share/guestfs/appliance/ virt-make-fs --format=qcow2 --partition=gpt --type=ext4 --size=40G /mnt/gentoo/ gentoo-riscv64.qcow2
いよいよ VM を実行。前述のとおりブートローダに Debian の u-boot-qemu の U-Boot バイナリを使っている。-kernel
パラメータに u-boot.elf (./usr/lib/u-boot/qemu-riscv64_smode/uboot.elf)
を指定する。
$ qemu-system-riscv64 -nographic -machine virt -m 2G \
-kernel uboot.elf \
-object rng-random,filename=/dev/urandom,id=rng0 -device virtio-rng-device,rng=rng0 \
-device virtio-blk-device,drive=hd0 -drive file=gentoo-rscv64.qcow2,format=qcow2,id=hd0 \
-device virtio-net-device,netdev=usernet -netdev user,id=usernet
ログインプロンプトが出てきたら嬉しい。最後にクリーンアップ。
# rm /stage3-*.tar.*
# rm /usr/bin/qemu-riscv64
参考
- デイビッド・パターソン、アンドリュー・ウォーターマン、成田 光彰 訳 (2018) 『RISC-V 原典』 日経 BP 社
- RISC-V – Wikipedia: https://en.wikipedia.org/wiki/RISC-V
- Project:RISC-V – Gentoo Wiki: https://wiki.gentoo.org/wiki/Project:RISC-V
- RISC-V – Debian Wiki: https://wiki.debian.org/RISC-V
- Embedded Handbook/General/Compiling with qemu user chroot – Gentoo Wiki: https://wiki.gentoo.org/wiki/Embedded_Handbook/General/Compiling_with_qemu_user_chroot
Hi! When I chroot in my /mnt/gentoo, it said could not find /bin/bash: No such file or directory. Have you faced it?
I don’t think I have faced it. I wonder if the file exists—what would you get if you tried `file /mnt/gentoo/bin/bash`?