PS: This article was first published on the GTOC WeChat public account of the Gewei open-source community.

There is currently not much hardware that supports the RISC-V virtualization extension. For readers who want to try it out, QEMU can be used to emulate it. The following provides a detailed tutorial.

The basic idea is to use QEMU to software-emulate a RISC-V SoC (the virt machine), run an Ubuntu distribution on it, and then use virtualization inside Ubuntu to run Linux.

  1. Basic environment preparation.

Using an Ubuntu system on the host (x86-64) as an example, you need to install the following packages:

sudo apt update
sudo apt install opensbi qemu-system-misc u-boot-qemu

If you want to try the latest QEMU, you can download it from the official website and build it manually.

You also need to prepare an Ubuntu image for RISC-V, which will be used as the software environment for RISC-V hardware virtualization. You can download it directly from the Ubuntu official website (because the download links change frequently, and to avoid broken links, this article does not include them). Here I recommend using the preinstalled version, since you do not need to install the operating system manually.

After downloading the image, you need to decompress and expand it:

# Decompress the downloaded image
xz -dk ubuntu-24.04.2-preinstalled-server-riscv64.img.xz
# Resize the image
qemu-img resize -f raw ubuntu-24.04-preinstalled-server-riscv64.img +5G

Start the RISC-V Ubuntu image with the following command:

qemu-system-riscv64 \
    -machine virt -nographic -m 4096 -smp 32 \
    -kernel /usr/lib/u-boot/qemu-riscv64_smode/uboot.elf \
    -device virtio-net-device,netdev=eth0 -netdev user,id=eth0,hostfwd=tcp::2222-:22 \
    -device virtio-rng-pci \
    -drive file=ubuntu-25.04-preinstalled-server-riscv64.img,format=raw,if=virtio

Here we configure the virt machine to run the guest operating system (virt has H-extension support enabled by default), without a graphical interface, by printing the guest serial output to the command-line terminal and allowing interactive use.

The first boot stage for QEMU on RISC-V is OpenSBI. Before version 7.0, it had to be specified with the -bios option; in later versions, QEMU loads it automatically by default, so no manual specification is needed. The second stage uses U-Boot to boot the kernel.

We also allocated 4 GiB of memory and 32 vCPU cores (the maximum number supported by U-Boot). In addition, we configured network pass-through and mapped the guest’s port 22 to host port 2222, so that the virtual machine can be accessed via remote connection tools such as SSH.

  1. Configure RISC-V Ubuntu.

After Ubuntu starts successfully, you will see the following output. We use the default username ubuntu to log in and change the initial password ubuntu to the one you need, as follows:

...
[  OK  ] Started getty@tty1.service - Getty on tty1.
[  OK  ] Reached target getty.target - Login Prompts.
Ubuntu 25.04 ubuntu ttyS0
ubuntu login: ubuntu # enter the username
Password: ubuntu # enter the password; you will then be prompted to change the initial password
...
Welcome to Ubuntu 25.04 (GNU/Linux 6.14.0-13-generic riscv64)

After successfully logging in, we can briefly verify whether the guest operating system supports virtualization:

grep isa /proc/cpuinfo 
isa             : rv64imafdch_zicbom_zicboz_ziccrse_zicntr_zicsr_zifencei_zihintntl_zihintpause_zihpm_zawrs_zfa_zca_zcd_zba_zbb_zbc_zbs_sstc_svadu_svvptc
...

You can see that the isa field for all 32 CPUs contains the h extension character, which indicates that the hardware we are emulating supports virtualization extensions.

Next, configure the environment. To make it easier to use virtualization to run Linux, we can still use QEMU for this. First install the necessary packages (since network pass-through is enabled, you can install them directly):

sudo apt update; sudo apt upgrade -y
sudo apt install qemu-system

We use the RISC-V virtualization test image and scripts provided by Revyos for verification:

sudo apt install -y wget # If wget is not installed on the system, install it first
wget https://mirror.iscas.ac.cn/revyos/extra/kvm_demo/rootfs_kvm_guest.img \
https://mirror.iscas.ac.cn/revyos/extra/kvm_demo/start_vm.sh \
https://mirror.iscas.ac.cn/revyos/extra/kvm_demo/Image
chmod +x start_vm.sh; ./start_vm.sh # Start KVM

After a successful start, the output is as follows:

...
[    6.538768] Freeing unused kernel image (initmem) memory: 2200K
[    6.561827] Run /init as init process
           _  _
          | ||_|
          | | _ ____  _   _  _  _
          | || |  _ \| | | |\ \/ /
          | || | | | | |_| |/    \
          |_||_|_| |_|\____|\_/\_/\_/

               Busybox Rootfs
Please press Enter to activate this console.
/ # uname -a
Linux (none) 6.6.30 #1 SMP Sat May 11 15:15:11 UTC 2024 riscv64 GNU/Linux
/ #

From here on, you can enjoy the RISC-V KVM virtualization experience~