https://medium.com/@e1d1/risc-v-simulation-with-qemu-61ea8f2d8f4b
Installation of Qemu
On the Qemu website, you can find a lot of information on how to get it running. But for the specific purpose of this tutorial, a few important extra steps are needed.
In order to use the user mode simulation, your host system must be Linux. I recommend installing from source as described on this site using configure with –target-list= riscv32-linux-user,riscv64-linux-user, riscv32-softmmu,riscv64-softmmu as a configuration. I assume you have a RV toolchain running, if not, here is how.
User-Mode
The simplest way of getting an environment for RV programming is the user mode of Qemu. You cross compile your program as if it were on an RV system running Linux. Then you run your program with Qemu user mode.
To illustrate, I give a short example of compiling and running a C program. I assume you have a running set up for Linux.
echo -e '#include <stdio.h>\nint main(){\n printf("hi\\n");\n return 0;\n}' > hi.c
riscv64-unknown-elf-gcc -o hi hi.c
qemu-riscv64-static hi
System-Mode
The system mode of Qemu lets you simulate a complete operating system. For example, you can run Linux inside this simulation. You can change (e.b. log in) to this guest system, install all tools you need and run your own RV programs. However, depending on the system chosen, you might need to cross compile your program on your host and transfer your program to the simulated guest system.
To make these steps a bit easier, I will show you how to get a Linux system up for an RV32 using Buildroot and for an RV64 using Debian.
RV32: Linux using Buildroot
This is very easy to achieve. Get Buildroot and build:
git clone https://git.buildroot.net/buildroot
make qemu_riscv32_virt_defconfig
make
Note, you can customize your Buildroot system before make
with make menuconfig
, for example, to install gdbserver
. Then run Qemu with
qemu-system-riscv32 \
-M virt \
-bios output/images/fw_jump.elf \
-kernel output/images/Image \
-append "root=/dev/vda ro" \
-drive file=output/images/rootfs.ext2,format=raw,id=hd0 \
-device virtio-blk-device,drive=hd0 \
-netdev user,id=net0 -device virtio-net-device,netdev=net0
These options do the following:
-M virt
: emulated machine is of typevirt
which is just a general machine type for simulation.-bios output/images/fw_jump.elf
: bios image generated by Buildroot.-kernel output/images/Image
: kernel image generated by Buildroot.-append "root=/dev/vda ro"
: command line for the kernel which defines the root filesystem/dev/vda
read-only, which is the virtualized hard drive.-drive file=output/images/rootfs.ext2,format=raw,id=hd0
: specifies the drivehd0
from the file generated by Buildroot in raw format.-device virtio-blk-device,drive=hd0
: adds the device driver for the drivehd0
.-netdev user,id=net0
: network user mode with idnet0
.-device virtio-net-device,netdev=net0
: specifies the network driver fornet0
.
RV64: Linux using Debian
Fortunately, there are a Debian pre-baked images available here. Just download the RV64 image, extract and run with Qemu. In the extracted folder, you can follow the instructions of the readme.txt
file.
qemu-system-riscv64 -machine virt -cpu rv64 -m 1G -device virtio-blk-device,drive=hd -drive file=image.qcow2,if=none,id=hd -device virtio-net-device,netdev=net -netdev user,id=net,hostfwd=tcp::2222-:22 -bios /usr/lib/riscv64-linux-gnu/opensbi/generic/fw_jump.elf -kernel /usr/lib/u-boot/qemu-riscv64_smode/uboot.elf -object rng-random,filename=/dev/urandom,id=rng -device virtio-rng-device,rng=rng -nographic -append "root=LABEL=rootfs console=ttyS0"
Many options are explained above. Further options are:
-cpu rv64
: RV64 processor simulation.-m 1G
: use 1GB RAM.-drive file=image.qcow2,if=none,id=hd
: defines theimage.qcow2
as hard drive with interface none.... ,hostfwd=tcp::2222-:22
: forwards the port 2222 of the host to the port 22 of the guest. This enables ssh login.-object rng-random,filename=/dev/urandom,id=rng
: creates the objectrng-random
with idrng
.-device virtio-rng-device,rng=rng
: defines the type of idrng
.
As you can see, you might need OpenSBI and U-Boot for Qemu. However, Linux distributions like Debian already have packages for this (opensbi
, u-boot-qemu
).
Other options you might find useful are:
-device VGA
: for getting graphics, e.g. X11.-vnc :1
: for remote login with vnc using display:1
of your host.-device virtio-keyboard,serial=virtio-keyboard
: for getting a keyboard using X11.-device virtio-mouse-pci
: for a mouse with X11.-serial pty
: for a serial interface with/dev/pty
of your host, the number will be displayed by start.-fsdev local,id=sf,path=/tmp/mnt,security_model=mapped-file
for a shared folder using/tmp/mnt/
of your host with idsf
.-device virtio-9p-pci,fsdev=sf,mount_tag=sf_tag
for defining a mount tag for sharing usingmount -t 9p sf_tag /mymount/point
.
You can quit Qemu with Ctrl-A X and switch between its monitor and the simulation with Ctrl-A C.
For example, the following command lets you share files from the host (/tmp/host/)
to the guest system (mount -t 9p sf_tag /tmp/guest/
), forward two ports (22 and 1234) and login via vnc:
qemu-system-riscv64 -device VGA -machine virt -cpu rv64 -smp 4 -m 4G -kernel /usr/lib/u-boot/qemu-riscv64_smode/uboot.elf -device virtio-blk-device,drive=hd -drive file=image.qcow2,if=none,id=hd -device virtio-net-device,netdev=net -netdev user,id=net,hostfwd=tcp::2222-:22,hostfwd=tcp::12345-:1234 -object rng-random,filename=/dev/urandom,id=rng -device virtio-rng-device,rng=rng -append "root=LABEL=rootfs console=ttyS0" -device virtio-keyboard,serial=virtio-keyboard -device virtio-mouse-pci -serial pty -fsdev local,id=sf,path=/tmp/host,security_model=mapped-file -device virtio-9p-pci,fsdev=sf,mount_tag=sf_tag -vnc :1