Ubuntu Weekly Recipe

第603回 RISC-VのDebianイメージをQEMUで動かす

この記事を読むのに必要な時間:およそ 9.5 分

RISC-Vのルートファイルシステムの作成

まずはルートファイルシステム構築に必要なパッケージをインストールしておきましょう。

$ sudo apt install debootstrap \
    debian-ports-archive-keyring \
    qemu-user-static binfmt-support

debootstrapはDebianのベースシステムを構築するためのツールで※3⁠,debian-ports-archive-keyringはDebian Ports用のリポジトリを検証するための公開鍵です。

※3
ちなみに今回はdebootstrapを使いますが,より小さいルートファイルシステムを作りたいなら第594回「mmdebstrapで最小のルートファイルシステムを作る」で紹介しているmmdebstrapコマンドを使うという手もあります。

qemu-user-staticとbinfmt-supportは,構築したルートファイルシステムでRISC-Vバイナリを実行するためにインストールしています。

次にルートファイルシステムを作成します。

$ mkdir riscv && cd $_
$ sudo debootstrap --arch=riscv64 \
  --keyring /usr/share/keyrings/debian-ports-archive-keyring.gpg \
  --include=debian-ports-archive-keyring \
  unstable rootfs-riscv64 \
  http://deb.debian.org/debian-ports

--keyringでは先ほどインストールしたPorts用のリポジトリ鍵を指定しています。さらに--includeでルートファイルシステムにPorts用のリポジトリ鍵を含むパッケージをインストールしています。

ちなみに今回はコード名にunstableを指定しています。Ports向けリポジトリで他に指定できるのはexperimentalとPorts固有のテスト環境であるunreleasedのみです。そのためタイミングが悪いと,特にたまたま依存関係を満たせない変更が行われた場合などに,構築に失敗することがあります。たとえば2020年1月18日時点では,isc-dhcp-clientの4.4.1-2がlibdns-export1104とlibisc-export1100に依存しているものの,これらを提供するbind9の最新版である1:9.11.14+dfsg-3までにおいて,それぞれlibdns-export1107libisc-export1104になってしまったために,isc-dhcp-clientをインストールできないという問題がありました。

もしうまくルートファイルシステムを作れないようならsnapshot.debian.orgのリポジトリを使うと良いでしょう。RISC-Vだと少なくとも2019年12月19日時点のリポジトリだと問題はありませんでした※4⁠。

※4
要するにそのときにテストした際は問題なかったものの,今回の記事の執筆にあたって改めて試したら本問題にひっかかったという状態です。bind9パッケージの更新が2020年1月3日ぐらいのようですので,それより少し前のリポジトリなら問題ないかもしれません。実際,2020年1月3日の02:54:42でも無事に構築できました。

特定の日付のリポジトリを使うなら,次のように最後の引数にあるリポジトリURLを変更します。

$ sudo debootstrap --arch=riscv64 \
  --keyring /usr/share/keyrings/debian-ports-archive-keyring.gpg \
  --include=debian-ports-archive-keyring \
  unstable rootfs-riscv64 \
  https://snapshot.debian.org/archive/debian-ports/20191219T030209Z

ただしこの場合,最新のパッケージを導入できません。ルートファイルシステム構築後に/etc/sources.listに両方のリポジトリを書くなど,なんらかの対応を行っておきましょう。具体的な手順は後ほど説明します。

この時点でルートファイルシステムのサイズは300MiB弱程度のようです。

$ sudo du -hs rootfs-riscv64/
295M    rootfs-riscv64/

ルートファイルシステムを構築したら,そのルートファイルシステムにchrootし,追加の設定を行います。

$ sudo chroot rootfs-riscv64
root@riscv:/#

まずはリポジトリデータのアップデートです。特にsnapshot.debian.orgを使用して構築したのなら,Portsのリポジトリも指定してパッケージを更新しておいたほうがいいかもしれません。

root@riscv:/# echo "deb http://deb.debian.org/debian-ports unstable main" \
  >> /etc/apt/sources.list
root@riscv:/# apt update
Get:1 http://deb.debian.org/debian-ports unstable InRelease [56.0 kB]
Hit:2 https://snapshot.debian.org/archive/debian-ports/20191219T030209Z unstable InRelease
Get:3 http://deb.debian.org/debian-ports unstable/main all Packages [8379 kB]
Get:4 http://deb.debian.org/debian-ports unstable/main riscv64 Packages [20.4 MB]
Fetched 28.8 MB in 17s (1658 kB/s)
Reading package lists... Done
Building dependency tree... Done
24 packages can be upgraded. Run 'apt list --upgradable' to see them.
root@riscv:/# apt full-upgrade

ネットワーク設定が空なので,QEMUで動かした時のためにDHCPでアドレスを取得できるようにしておきます。

root@riscv:/# cat /etc/network/interfaces
# interfaces(5) file used by ifup(8) and ifdown(8)
# Include files from /etc/network/interfaces.d:
source-directory /etc/network/interfaces.d

ローカルループバック用の設定
root@riscv:/# cat >>/etc/network/interfaces.d/lo <<EOF
auto lo
iface lo inet loopback
EOF

eth0用の設定
root@riscv:/# cat >>/etc/network/interfaces.d/eth0 <<EOF
auto eth0
iface eth0 inet dhcp
EOF

次にアカウントを作成しておきましょう。

root@riscv:/# adduser shibata
Adding user `shibata' ...
Adding new group `shibata' (1000) ...
Adding new user `shibata' (1000) with group `shibata' ...
Creating home directory `/home/shibata' ...
Copying files from `/etc/skel' ...
New password:
Retype new password:
passwd: password updated successfully
Changing the user information for shibata
Enter the new value, or press ENTER for the default
        Full Name []: Mitsuya Shibata
        Room Number []:
        Work Phone []:
        Home Phone []:
        Other []:
Is the information correct? [Y/n]

rootアカウントのパスワードはロックされています。管理者権限に昇格できるよう,sudoパッケージをインストールして,先ほど作成したアカウントをsudoグループに追加しておきます。あくまでテスト用と割り切るなら,passwdコマンドでrootアカウントのパスワードを設定して,rootアカウントのまま生活する方法もあります。

root@riscv:/# apt install sudo
root@riscv:/# usermod -aG sudo shibata
root@riscv:/# id shibata
uid=1000(shibata) gid=1000(shibata) groups=1000(shibata),27(sudo)

QEMU上だとhvc0はttyS0と同じデバイスになるため,hvc0側のgettyの起動を抑制しておきます。

root@riscv:/# ln -sf /dev/null /etc/systemd/system/serial-getty@hvc0.service

カーネルとブートローダーをインストールして,ブートローダーの設定も行っておきましょう。

root@riscv:/# apt install linux-image-riscv64 u-boot-menu

カーネルのインストール時に次のようなエラーが大量に表示されるかもしれません。

depmod: ERROR: ../libkmod/libkmod.c:515 lookup_builtin_file() could not open builtin file '/lib/modules/5.4.0-2-riscv64/modules.builtin.bin'
depmod: ERROR: ../libkmod/libkmod.c:515 lookup_builtin_file() could not open builtin file '/var/tmp/mkinitramfs_SdQixj/lib/modules/5.4.0-2-ris
cv64/modules.builtin.bin'

どうやらこれはinitramfs-toolsの不具合のようです。とりあえずパッケージに組み込まれているinitramfsをそのまま使うのであれば実害はないはずなので,現時点では無視してください※5⁠。

※5
「エラーを無視してください」と書くのは非常に心苦しいのでより正しい言い方をお伝えしておくと,⁠Debian側の修正に協力してください」となります。

ブートローダーはU-Bootを使います。そこで次のように設定し,その値を反映しておきます。

root@riscv:/# cat >>/etc/default/u-boot <<EOF
U_BOOT_PARAMETERS="rw noquiet root=/dev/vda1"
U_BOOT_FDT_DIR="noexist"
EOF
root@riscv:/# u-boot-update
P: Checking for EXTLINUX directory... found.
/usr/bin/cat: /proc/cmdline: No such file or directory
P: Writing config for vmlinux-5.4.0-2-riscv64...
P: Updating /boot/extlinux/extlinux.conf...

U_BOOT_FDT_DIR="noexist"には「存在しないディレクトリ」を指定します。これはDebianのカーネルが5.3.0からRISC-V用のDTBをビルドするようになったことに対する回避策です。通常は適切なディレクトリにSoCごとのDTBをインストールし,起動時にそれを選択することが正しいやりかたです。しかしながらQEMU用のDTBはインストールされていません。そこで「存在しないディレクトリ」を指定することでDTBが見つからないようにしておき,QEMUインスタンスの特定のアドレスにあるDTBデータを使うようにしているというわけです。このあたりは将来的にもう少しスマートな方法に変わる予定です。

ルートファイルシステム内部の設定が終わったので,chrootから抜けておきましょう。

root@riscv:/# exit

最後に作成したルートファイルシステムをQEMUイメージに変換します。方法はいくつか存在しますが,ここではvirt-make-fsコマンドを使いましょう。

$ sudo apt install --no-install-recommends libguestfs-tools
$ sudo virt-make-fs --partition --type=ext4 --size=10G rootfs-riscv64/ rootfs-riscv64.img
$ sudo chown ${USER} rootfs-riscv64.img

これでイメージの作成は完了です。

著者プロフィール

柴田充也(しばたみつや)

Ubuntu Japanese Team Member株式会社 創夢所属。数年前にLaunchpad上でStellariumの翻訳をしたことがきっかけで,Ubuntuの翻訳にも関わるようになりました。