FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

KVM on QEMUでRISC-Vのハイパーバイザーを試す

RISC-Vのハイパーバイザー拡張は現在Version0.61まで進んでいるが、実際にアプリケーションを試す手法としてLinux上でKVMを動かしてさらにLinuxを立ち上げるというものがある。チュートリアルが公開されているので試してみたい。

以下の資料に基づいて試してみることにする。

github.com

まずQEMUをビルドする。本家からのダウンロードではないが、ハイパーバイザ―向けに拡張が実装してあるのかどうかは良く分からない。

git clone https://github.com/kvm-riscv/qemu.git
cd qemu
./configure --target-list="riscv32-softmmu riscv64-softmmu"
make
cd ..

次にOpenSBIをダウンロードしてビルドする。これについても知識が足りずに良く分からないのだが、M-Mode動作するランタイムファームウェアのことらしい。詳しいことは全く分からない。

git clone https://github.com/riscv/opensbi.git
cd opensbi
export CROSS_COMPILE=riscv64-unknown-linux-gnu-
make PLATFORM=generic
cd ..

次はLinuxカーネルのビルドだ。今回はホストとゲストで同じカーネルを使用するため2種類ビルドする必要はない。

git clone https://github.com/kvm-riscv/linux.git
export ARCH=riscv
export CROSS_COMPILE=riscv64-unknown-linux-gnu-
mkdir build-riscv64
make -C linux O=`pwd`/build-riscv64 defconfig
make -C linux O=`pwd`/build-riscv64

次に必要なのはlibfdtというライブラリで、これはクロスコンパイラでライブラリとして必要らしい。KVMTOOLをコンパイルするためにはこのlibfdtが必要なようだ。従ってクロスコンパイラがインストールされているディレクトリに対してビルドしたライブラリを格納することになる。

git clone git://git.kernel.org/pub/scm/utils/dtc/dtc.git
cd dtc
export ARCH=riscv
export CROSS_COMPILE=riscv64-unknown-linux-gnu-
export CC="${CROSS_COMPILE}gcc -mabi=lp64d -march=rv64gc"
TRIPLET=$($CC -dumpmachine)
SYSROOT=$($CC -print-sysroot)
make libfdt
make EXTRA_CFLAGS="-mabi=lp64d" DESTDIR=$SYSROOT PREFIX=/usr LIBDIR=/usr/lib64/lp64d install-lib install-includes
cd ..

上記のコマンドを試しているうちに、

TRIPLET=$($CC -dumpmachine)
SYSROOT=$($CC -print-sysroot)

でなぜかエラーが発生する。原因も良く分からなかったので決め打ちで変数を設定してしまった。

$ riscv64-unknown-linux-gnu-gcc -mabi=lp64d -march=rv64gc -dumpmachine
riscv64-unknown-linux-gnu
$ TRIPLET=riscv64-unknown-linux-gnu
$ riscv64-unknown-linux-gnu-gcc -mabi=lp64d -march=rv64gc -print-sysroot
/home/msyksphinz/riscv64-ctng-linux/riscv64-unknown-linux-gnu/sysroot
$ SYSROOT=/home/msyksphinz/riscv64-ctng-linux/riscv64-unknown-linux-gnu/sysroot

ここでさらに問題発生、make EXTRA_CFLAGS="-mabi=lp64d" DESTDIR=$SYSROOT PREFIX=/usr LIBDIR=/usr/lib64/lp64d install-lib install-includesを実行すると以下のエラーを吐いて落ちてしまった。

        CHK version_gen.h
         PYMOD pylibfdt/_libfdt.so
/usr/bin/ld: build/temp.linux-x86_64-3.7/libfdt_wrap.o: Relocations in generic ELF (EM: 243)
/usr/bin/ld: build/temp.linux-x86_64-3.7/libfdt_wrap.o: Relocations in generic ELF (EM: 243)
/usr/bin/ld: build/temp.linux-x86_64-3.7/libfdt_wrap.o: Relocations in generic ELF (EM: 243)
/usr/bin/ld: build/temp.linux-x86_64-3.7/libfdt_wrap.o: Relocations in generic ELF (EM: 243)
/usr/bin/ld: build/temp.linux-x86_64-3.7/libfdt_wrap.o: Relocations in generic ELF (EM: 243)
/usr/bin/ld: build/temp.linux-x86_64-3.7/libfdt_wrap.o: Relocations in generic ELF (EM: 243)
/usr/bin/ld: build/temp.linux-x86_64-3.7/libfdt_wrap.o: Relocations in generic ELF (EM: 243)
/usr/bin/ld: build/temp.linux-x86_64-3.7/libfdt_wrap.o: Relocations in generic ELF (EM: 243)
/usr/bin/ld: build/temp.linux-x86_64-3.7/libfdt_wrap.o: Relocations in generic ELF (EM: 243)
/usr/bin/ld: build/temp.linux-x86_64-3.7/libfdt_wrap.o: error adding symbols: file in wrong format
collect2: error: ld returned 1 exit status

これは同じページのIssueで調べてみると、別のクロスコンパイラツールチェインが必要らしい。

https://github.com/kvm-riscv/howto/issues/2

という訳で https://toolchains.bootlin.com/ からRISC-V向けのツールチェインを新たにダウンロードして、dtc/MakefilePythonのパスを書き換えた。

  • dtc/Makefile
git diff
diff --git a/Makefile b/Makefile
index c187d5f..6472882 100644
--- a/Makefile
+++ b/Makefile
@@ -29,7 +29,7 @@ BISON = bison
 LEX = flex
 SWIG = swig
 PKG_CONFIG ?= pkg-config
-PYTHON ?= python3
+PYTHON ?= $(HOME)/riscv-toolchains/riscv64--glibc--bleeding-edge-2020.02-2/bin/python3

 INSTALL = /usr/bin/install
 INSTALL_PROGRAM = $(INSTALL)

再度ビルドすると上手く行ったようだ。

$ make EXTRA_CFLAGS="-mabi=lp64d" DESTDIR=$SYSROOT PREFIX=/usr LIBDIR=/usr/lib64/lp64d install-lib install-includes
        CHK version_gen.h
        UPD version_gen.h
         DEP util.c
        CHK version_gen.h
         CC util.o
         LD convert-dtsv0
         LD dtc
         LD fdtdump
         LD fdtget
         LD fdtput
         LD fdtoverlay
## Skipping pylibfdt (install python dev and swig to build)
         INSTALL-LIB
         INSTALL-INC

次にKVMTOOLをビルドする。これがKVMの本体なのか?

git clone https://github.com/kvm-riscv/kvmtool.git
export ARCH=riscv
export CROSS_COMPILE=riscv64-unknown-linux-gnu-
cd kvmtool
make lkvm-static
${CROSS_COMPILE}strip lkvm-static
cd ..

最後に、RootFSをビルドして、なかにKVMTOOLおよびゲストとして起動するLinuxカーネルをコピーしイメージとしてまとめ上げる。

export ARCH=riscv
export CROSS_COMPILE=riscv64-unknown-linux-gnu-
git clone https://github.com/kvm-riscv/howto.git
wget https://busybox.net/downloads/busybox-1.27.2.tar.bz2
tar -C . -xvf ./busybox-1.27.2.tar.bz2
mv ./busybox-1.27.2 ./busybox-1.27.2-kvm-riscv64
cp -f ./howto/configs/busybox-1.27.2_defconfig busybox-1.27.2-kvm-riscv64/.config
make -C busybox-1.27.2-kvm-riscv64 oldconfig
make -C busybox-1.27.2-kvm-riscv64 install
mkdir -p busybox-1.27.2-kvm-riscv64/_install/etc/init.d
mkdir -p busybox-1.27.2-kvm-riscv64/_install/dev
mkdir -p busybox-1.27.2-kvm-riscv64/_install/proc
mkdir -p busybox-1.27.2-kvm-riscv64/_install/sys
mkdir -p busybox-1.27.2-kvm-riscv64/_install/apps
ln -sf /sbin/init busybox-1.27.2-kvm-riscv64/_install/init
cp -f ./howto/configs/busybox/fstab busybox-1.27.2-kvm-riscv64/_install/etc/fstab
cp -f ./howto/configs/busybox/rcS busybox-1.27.2-kvm-riscv64/_install/etc/init.d/rcS
cp -f ./howto/configs/busybox/motd busybox-1.27.2-kvm-riscv64/_install/etc/motd
cp -f ./kvmtool/lkvm-static busybox-1.27.2-kvm-riscv64/_install/apps
cp -f ./build-riscv64/arch/riscv/boot/Image busybox-1.27.2-kvm-riscv64/_install/apps
cd busybox-1.27.2-kvm-riscv64/_install; find ./ | cpio -o -H newc > ../../rootfs_kvm_riscv64.img; cd -

これで作業ディレクトリの先頭にrootfs_kvm_riscv64.imgが出来上がる。これがQEMUで実行すべきイメージの本体だ。

早速QEMUで実行してみたいと思う。

$ ./qemu/riscv64-softmmu/qemu-system-riscv64 -cpu rv64,x-h=true -M virt -m 512M \
    -nographic -bios opensbi/build/platform/generic/firmware/fw_jump.bin \
    -kernel ./build-riscv64/arch/riscv/boot/Image -initrd ./rootfs_kvm_riscv64.img \
    -append "root=/dev/ram rw console=ttyS0 earlycon=sbi"

注記:こっちの方が正しい

./qemu/riscv64-softmmu/qemu-system-riscv64 -cpu rv64,x-h=true -M virt -m 512M -nographic -bios opensbi/opensbi/build/platform/generic/firmware/fw_jump.bin -kernel opensbi/build-riscv64/arch/riscv/boot/Image -initrd ./rootfs_kvm_riscv64.img -append "root=/dev/ram rw console=ttyS0 earlycon=sbi"
[    0.641813] mousedev: PS/2 mouse device common for all mice
[    0.649317] goldfish_rtc 101000.rtc: registered as rtc0
[    0.651412] goldfish_rtc 101000.rtc: setting system clock to 2020-09-25T12:05:29 UTC (1601035529)
[    0.656422] syscon-poweroff soc:poweroff: pm_power_off already claimed (____ptrval____) sbi_shutdown
[    0.658333] syscon-poweroff: probe of soc:poweroff failed with error -16
[    0.661627] usbcore: registered new interface driver usbhid
[    0.662493] usbhid: USB HID core driver
[    0.666716] NET: Registered protocol family 10
[    0.677816] Segment Routing with IPv6
[    0.679190] sit: IPv6, IPv4 and MPLS over IPv4 tunneling driver
[    0.685464] NET: Registered protocol family 17
[    0.689903] 9pnet: Installing 9P2000 support
[    0.691462] Key type dns_resolver registered
[    0.750053] Freeing unused kernel memory: 232K
[    0.753651] Run /init as init process
           _  _
          | ||_|
          | | _ ____  _   _  _  _
          | || |  _ \| | | |\ \/ /
          | || | | | | |_| |/    \
          |_||_|_| |_|\____|\_/\_/

               Busybox Rootfs

Please press Enter to activate this console.
/ #

いいぞ、起動した。次にLinux上でKVMを立ち上げてされにLinuxを起動する。

$ ./apps/lkvm-static run -m 128 -c2 --console serial -p "console=ttyS0 earlycon=uart8250,mmio,0x3f8" -k ./apps/Image --debug
          | ||_|
          | | _ ____  _   _  _  _
          | || |  _ \| | | |\ \/ /
          | || | | | | |_| |/    \
          |_||_|_| |_|\____|\_/\_/

               Busybox Rootfs

Please press Enter to activate this console.
/ # ./apps/lkvm-static run -m 128 -c2 --console serial -p "console=ttyS0 earlyco
n=uart8250,mmio,0x3f8" -k ./apps[   15.277346] random: fast init done
/Image --debug
  # lkvm run -k ./apps/Image -m 128 -c 2 --name guest-45
  Info: (riscv/kvm.c) kvm__arch_load_kernel_image:116: Loaded kernel to 0x80200000 (17191724 bytes)
  Info: (riscv/kvm.c) kvm__arch_load_kernel_image:128: Placing fdt at 0x81800000 - 0x87ffffff
  # Warning: The maximum recommended amount of VCPUs is 1
  Info: (virtio/mmio.c) virtio_mmio_init:326: virtio-mmio.devices=0x200@0x10000000:5
  Info: (virtio/mmio.c) virtio_mmio_init:326: virtio-mmio.devices=0x200@0x10000200:6
  Info: (virtio/mmio.c) virtio_mmio_init:326: virtio-mmio.devices=0x200@0x10000400:7
[    0.000000] OF: fdt: Ignoring memory range 0x80000000 - 0x80200000
[    0.000000] Linux version 5.9.0-rc3-00338-g0b92c1839cb1 (msyksphinz@DESKTOP-P42Q0NR) (riscv64-unknown-linux-gnu-gcc (crosstool-NG 1.24.0) 8.3.0, GNU ld (crosstool-NG 1.24.0) 2.32) #1 S
MP Thu Sep 24 23:07:36 JST 2020
[    0.000000] earlycon: uart8250 at MMIO 0x00000000000003f8 (options '')
[    0.000000] printk: bootconsole [uart8250] enabled
[    0.000000] Zone ranges:
[    0.000000]   DMA32    [mem 0x0000000080200000-0x0000000087ffffff]
[    0.000000]   Normal   empty
[    0.000000] Movable zone start for each node
[    0.000000] Early memory node ranges
[    0.000000]   node   0: [mem 0x0000000080200000-0x0000000087ffffff]
[    0.000000] Initmem setup node 0 [mem 0x0000000080200000-0x0000000087ffffff]
[    0.000000] software IO TLB: mapped [mem 0x83e3b000-0x87e3b000] (64MB)
[    0.000000] SBI specification v0.1 detected
[    0.000000] riscv: ISA extensions acdfimsu
[    0.000000] riscv: ELF capabilities acdfim
...
[    5.766641] IP-Config: Got DHCP answer from 192.168.33.1, my address is 192.168.33.15
[    5.817703] IP-Config: Complete:
[    5.838870]      device=eth0, hwaddr=02:15:15:15:15:15, ipaddr=192.168.33.15, mask=255.255.255.0, gw=192.168.33.1
[    5.895798]      host=192.168.33.15, domain=, nis-domain=(none)
[    5.931718]      bootserver=192.168.33.1, rootserver=0.0.0.0, rootpath=
[    5.931835]      nameserver0=192.168.33.1
[    6.059811] VFS: Mounted root (9p filesystem) on device 0:15.
[    6.115593] devtmpfs: mounted
[    6.193090] Freeing unused kernel memory: 232K
[    6.264232] Run /virt/init as init process
Mounting...
/ # [   10.820410] random: fast init done

Linuxの上でLinuxが立ち上がったぞ(正確にはWindows上で動かしているWSLの上でQEMUを立ち上げてそのうえでRISC-V Linuxを動かしその上でゲストのRISC-V Linuxを動かしている)ややこしい。

f:id:msyksphinz:20200925211715g:plain