Xv6-RISCVを試してみた

2020-11-13

以前MITのOS教材として使われているというxv6というOSを動かしてみた。 これは普段使っているパソコンのCPU(Intel x86)がターゲットとなっていて動かして試せるので、非常にモチベがあがる。

しかししばらく前からMITはオープンソースなCPUのRISCVをターゲットとした別のリポジトリxv6-riscvに移行してしまい、x86版のリポジトリはほぼ更新されない状態になってしまった。 RISCV版を動かすための開発・動作環境をどう用意するのか難しくないかと移行をためらっていたが、ようやく腰を上げて試してみた。

動作環境:macOS Catalina

qemu

brew install qemu で入るのかな? すでにインストール済みだった:

$ which qemu-system-riscv64
/usr/local/bin/qemu-system-riscv64
$ qemu-system-riscv64 --version
QEMU emulator version 5.1.0
Copyright (c) 2003-2020 Fabrice Bellard and the QEMU Project developers

RISCVツールチェインのインストール

https://github.com/riscv/homebrew-riscv に書かれている手順に従って、Homebrew でインストール:

$ brew tap riscv/riscv
$ brew install riscv-tools

/usr/local/bin/ 内にシンボリックリンクが貼られる。

$ ls /usr/local/bin/riscv64-*
/usr/local/bin/riscv64-unknown-elf-addr2line /usr/local/bin/riscv64-unknown-elf-gdb
/usr/local/bin/riscv64-unknown-elf-ar /usr/local/bin/riscv64-unknown-elf-gdb-add-index
/usr/local/bin/riscv64-unknown-elf-as /usr/local/bin/riscv64-unknown-elf-gprof
/usr/local/bin/riscv64-unknown-elf-c++ /usr/local/bin/riscv64-unknown-elf-ld
/usr/local/bin/riscv64-unknown-elf-c++filt /usr/local/bin/riscv64-unknown-elf-ld.bfd
/usr/local/bin/riscv64-unknown-elf-cpp /usr/local/bin/riscv64-unknown-elf-lto-dump
/usr/local/bin/riscv64-unknown-elf-elfedit /usr/local/bin/riscv64-unknown-elf-nm
/usr/local/bin/riscv64-unknown-elf-g++ /usr/local/bin/riscv64-unknown-elf-objcopy
/usr/local/bin/riscv64-unknown-elf-gcc /usr/local/bin/riscv64-unknown-elf-objdump
/usr/local/bin/riscv64-unknown-elf-gcc-10.1.0 /usr/local/bin/riscv64-unknown-elf-ranlib
/usr/local/bin/riscv64-unknown-elf-gcc-ar /usr/local/bin/riscv64-unknown-elf-readelf
/usr/local/bin/riscv64-unknown-elf-gcc-nm /usr/local/bin/riscv64-unknown-elf-run
/usr/local/bin/riscv64-unknown-elf-gcc-ranlib /usr/local/bin/riscv64-unknown-elf-size
/usr/local/bin/riscv64-unknown-elf-gcov /usr/local/bin/riscv64-unknown-elf-strings
/usr/local/bin/riscv64-unknown-elf-gcov-dump /usr/local/bin/riscv64-unknown-elf-strip
/usr/local/bin/riscv64-unknown-elf-gcov-tool

自分でビルドする場合

riscv/riscv-gnu-toolchain をビルドするとのこと。 ./configure --prefix= でインストール先を指定するが、 /opt/riscv だと管理者権限を要求する?かよくわからなかったので、自分のホーム以下にした。

make すると途中エラーで失敗してしまう。 Issueに上がっているのと同じで、 free 関数が定義されてないとかでコンパイルエラーが出る (Getting Issues on make on Mac ( Catalina) · Issue #745)。

参照しているサブモジュールの riscv-gdb が古い?ようで、更新したところビルドに成功した:

$ git clone --recursive https://github.com/riscv/riscv-gnu-toolchain.git  # サブモジュールもクローンされる
$ cd riscv-gnu-toolchain
$ git submodule update --remote riscv-gdb # risc-gdbサブモジュールを更新してやる
$ ./configure --prefix=$HOME/opt/riscv
$ make

configure で指定した ~/opt/riscvbin 内にツールチェインの実行ファイルがインストールされるので、パスを通してやる。

xv6-riscv のビルド

xv6-riscv をクローンして make する。 x86用のXV6ではホスト環境のgccなどがそのまま使えるが、RISCV用は先程ビルド・インストールしたツールチェインを使用する必要がある。 Makefile 内で判定して TOOLPREFIX 変数が設定されるようになっていて、 riscv64-(unknown-elf|linux-gnu-|unknown-linux-gnu-) が使用される。 (実行ファイルから判定されるので、ツールチェインを自分でビルドした場合にはインストールされた ~/opt/riscv にパスを通しておくこと。)

$ git clone https://github.com/mit-pdos/xv6-riscv
$ cd xv6-riscv
$ make # TOOLPREFIX=riscv64-unknown-elf-

make のターゲットに qemu を指定することで、qemu 上で実行できる:

$ make qemu
qemu-system-riscv64 -machine virt -bios none -kernel kernel/kernel -m 128M -smp 3 -nographic -drive file=fs.img,if=none,format=raw,id=x0 -device virtio-blk-device,drive=x0,bus=virtio-mmio-bus.0

xv6 kernel is booting

hart 2 starting
hart 1 starting
init: starting sh
$ ls
. 1 1 1024
.. 1 1 1024
README 2 2 2059
cat 2 3 24224
echo 2 4 23048
forktest 2 5 13272
grep 2 6 27528
init 2 7 23792
kill 2 8 22992
ln 2 9 22848
ls 2 10 26424
mkdir 2 11 23144
rm 2 12 23128
sh 2 13 41944
stressfs 2 14 23984
usertests 2 15 154472
grind 2 16 38120
wc 2 17 25312
zombie 2 18 22376
console 3 19 0
$

C-A x でqemuから抜けられる。

雑感

RISCV のクロスコンパイル環境やエミュレータが整ってるのがすごい。 その上にXV6も問題なく動いていうことなし。 RISCVのCPUをエミュレーションしている?はずなのに普通の速度で動作してしまうってすごすぎるんだが…。 考えてみればx86版も実機で動かしたことはなく動作確認はもっぱらqemuの-nographic経由だったので、 ユーザ側としてみればあまり違いはないかもしれない(そもそもそれがOSの目的だしね…)。

今後触ってみてx86版との違いや、RISCV版が想定しているハードウェア構成がどうなっているのかなどを見ていきたい。

参考

過去記事