RISC-V Gentoo インストールバトル

概要

RISC-V の VM イメージを作って、QEMU で動かしてみた。特にそれを使って何かをしようというわけではないけれど、『RISC-V 原典』を読み進められなかった (2 回目) 腹いせにやってみた。

そんなに大げさなことをやるわけではなく、既に RISC-V 用の stage 3 を作っている方々がおられる (https://wiki.gentoo.org/wiki/Project:RISC-V) ので、ありがたくそれを使ってインストールするのみである。ステップとしては以下のようになる。

  1. RISC-V の chroot 環境構築
  2. stage 3 を使用して chroot 環境に Gentoo インストール
  3. ディスクイメージにまとめて、ブートする

環境は以下のとおり。

  • ホスト 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

参考