RISC-Vのハイパーバイザー拡張は現在Version0.61まで進んでいるが、実際にアプリケーションを試す手法としてLinux上でKVMを動かしてさらにLinuxを立ち上げるというものがある。チュートリアルが公開されているので試してみたい。
以下の資料に基づいて試してみることにする。
まず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/MakefileのPythonのパスを書き換えた。
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を動かしている)ややこしい。
