ふとした理由でQEMU5.1.0でRISC-Vのテストコードを動かしたくてやり方をいろいろと調べていたのだがどうも見つからない。とりあえず以下のオプションを足してテストコードを動かしてみる。
$ git checkout v5.1.0 $ ../configure --target-list=riscv64-softmmu --disable-docs $ make -j4
以下のようにしてみた。
$ ./riscv64-softmmu/qemu-system-riscv64 --kernel /home/msyksphinz/work/riscv/riscv-tools/riscv-tests/build-rvg/benchmarks/dhrystone.riscv
qemu-system-riscv64: Unable to load the RISC-V firmware "opensbi-riscv64-spike-fw_jump.elf"
このエラーの意味が最初はさっぱりわからなかったのだが、どうもQEMUの最新バージョンではファームウェアを指定しなければLinuxのブートなどを全般的にできなくなっているようだ。ソースコードを読みつつ(というかソースコードを読まなければこれの解決方法が分からなかった)色々と試行した結果以下のようにしてみた
./riscv64-softmmu/qemu-system-riscv64 --bios none --kernel /home/msyksphinz/work/riscv/riscv-tools/riscv-tests/build-rvg/benchmarks/dhrystone.riscv
qemu-system-riscv64: HTIF tohost must be 8 bytes
えー、HITF
のtohost
なんて8バイトに設定してあると思うんだけどな。
riscv64-unknown-elf-readelf -a /home/msyksphinz/work/riscv/riscv-tools/riscv-tests/build-rvg/benchmarks/dhrystone.riscv | grep -e tohost -e fromhost
[ 2] .tohost PROGBITS 0000000080001000 00002000 01 .tohost .text .text.startup .rodata.str1.8 .rodata .sbss .bss 65: 0000000080001040 0 NOTYPE GLOBAL DEFAULT 2 fromhost 67: 0000000080001000 0 NOTYPE GLOBAL DEFAULT 2 tohost 70: 0000000080002928 20 FUNC GLOBAL DEFAULT 3 tohost_exit
あれ、サイズとしてはtohost
、fromhost
はゼロバイトなのか。じゃあエラーが発生してもおかしくはない。
とりあえずQEMU側を以下のように変更して問題が発生しないように調整してみた。
-Subproject commit 22ead3e0bfdb87516656453336160e0a37b066bf +Subproject commit 22ead3e0bfdb87516656453336160e0a37b066bf-dirty diff --git a/hw/riscv/riscv_htif.c b/hw/riscv/riscv_htif.c index ca87a5cf9f..d789295d2d 100644 --- a/hw/riscv/riscv_htif.c +++ b/hw/riscv/riscv_htif.c @@ -48,15 +48,15 @@ void htif_symbol_callback(const char *st_name, int st_info, uint64_t st_value, if (strcmp("fromhost", st_name) == 0) { address_symbol_set |= 1; fromhost_addr = st_value; - if (st_size != 8) { + if (st_size != 8 && st_size != 0) { error_report("HTIF fromhost must be 8 bytes"); exit(1); } } else if (strcmp("tohost", st_name) == 0) { address_symbol_set |= 2; tohost_addr = st_value; - if (st_size != 8) { - error_report("HTIF tohost must be 8 bytes"); + if (st_size != 8 && st_size != 0) { + error_report("HTIF tohost must be 8 bytes, st_size=%ld", st_size); exit(1); } }
./riscv64-softmmu/qemu-system-riscv64 --bios none --kernel /home/msyksphinz/work/riscv/riscv-tools/riscv-tests/build-rvg/benchmarks/dhrystone.riscv
qemu-system-riscv64: Failed to bind socket: Permission denied
ぬ、いろいろオプションを追加してみた。
./riscv64-softmmu/qemu-system-riscv64 --d in_asm --nographic --bios none --kernel /home/msyksphinz/work/riscv/riscv-tools/riscv-tests/build-rvg/benchmarks/dhrystone.riscv
0x0000000080002894: ffffe797 auipc a5,-8192 # 0x80000894 0x0000000080002898: 76e7b623 sd a4,1900(a5) 0x000000008000289c: ffffe697 auipc a3,-8192 # 0x8000089c 0x00000000800028a0: 7a468693 addi a3,a3,1956 0x00000000800028a4: 0006b783 ld a5,0(a3) 0x00000000800028a8: fe078ee3 beqz a5,-4 # 0x800028a4 ---------------- IN: putchar Priv: 3; Virt: 0 0x00000000800028a4: 0006b783 ld a5,0(a3) 0x00000000800028a8: fe078ee3 beqz a5,-4 # 0x800028a4
色々動き出したが、ここで止まってしまったようだ。putchar()
で止まってしまっている。おそらくRISC-V版Dhrystoneに埋め込まれているputchar()
の動きにQEMUが対応していないからだろう。何故ならば、BIOSのオプションをnoneにしてしまっているが本当はここに何らかのファームウェアを指定しなければならない。
https://github.com/riscv/opensbi
OpenSBIというのはその名の通りRISC-V向けのスーパバイザインタフェースのことで、RISC-Vのマシンモード向けの操作をプラットフォーム向けに規定する。Linuxなどはスーパバイザモードとユーザモードの動作を記述しているわけだが、マシンモードでは、例えば文字の出力の方法などを規定している。
$ git clone git@github.com:riscv/opensbi.git $ cd opensbi $ make CROSS_COMPILE=riscv64-unknown-elf- PLATFORM=generic
これでbuild/platform/generic/firmware/fw_jump.elf
が完成する。しかしこれをどのように使っていけばよいのだろう?
$ ./build/riscv64-softmmu/qemu-system-riscv64 --d in_asm --nographic --machine spike \ --bios /home/msyksphinz/work/riscv/opensbi/build/platform/generic/firmware/fw_payload.elf \ --kernel /home/msyksphinz/work/riscv/riscv-tools/riscv-tests/build-rvg/benchmarks/dhrystone.riscv
rom: requested regions overlap (rom phdr #0: /home/msyksphinz/work/riscv/riscv-tools/riscv-tests/build-rvg/benchmarks/dhrystone.riscv. free=0x0000000080017a60, addr=0x0000000080000000) qemu-system-riscv64: rom check and register reset failed
まず、QEMUがどのようなメモリマップになっているのかを確認する。このためにはDTBを出力してダンプしてみよう。
$ ./riscv64-softmmu/qemu-system-riscv64 --d in_asm --nographic --machine spike,dumpdtb=qemu-riscv64-spike.dtb --bios none $ ./riscv64-softmmu/qemu-system-riscv64 --d in_asm --nographic --machine virt,dumpdtb=qemu-riscv64-virt.dtb --bios none
$ dtc qemu-riscv64-spike.dtb > qemu-riscv64-spike.dts $ dtc qemu-riscv64-virt.dtb > qemu-riscv64-virt.dts
qemu-riscv64-spike.dts
/dts-v1/; / { #address-cells = < 0x02 >; #size-cells = < 0x02 >; compatible = "ucbbar,spike-bare-dev"; model = "ucbbar,spike-bare,qemu"; chosen { bootargs = [ 00 ]; }; ... htif { compatible = "ucb,htif0"; }; };
うーん、htif0
が入っているのは分かった。これをどのように接続すればいいんだ?メモリマップされているわけでもなさそうなので...すこし調査が必要だ。