QEMU provides good support for system-level RISC-V emulation. A full %%FreeBSD%% system can be run using its ''%%virt%%'' platform.
To run %%FreeBSD%%/RISC-V, QEMU version 5.0 or later is required. This can be installed via [[https://www.freshports.org/emulators/qemu50/|emulators/qemu50]] or [[https://www.freshports.org/emulators/qemu-devel/|emulators/qemu-devel]].
Also required is the %%OpenSBI%% bootloader, which can be installed from the [[https://www.freshports.org/sysutils/opensbi/|sysutils/opensbi]] port or package.
===== Generate a root filesystem =====
If you have built %%FreeBSD%% by hand and would like to generate a root filesystem and bootable image, you can follow these steps. If you downloaded a bootable %%FreeBSD%% image, skip to [[#Boot FreeBSD]].
**Create root partition**
# Install the system to a staging directory
setenv ROOTFSDIR $HOME/rootfsstage
make TARGET=riscv DESTDIR=$ROOTFSDIR NO_ROOT=yes installworld
make TARGET=riscv DESTDIR=$ROOTFSDIR NO_ROOT=yes installkernel
make TARGET=riscv DESTDIR=$ROOTFSDIR NO_ROOT=yes distribution
# Make any desired tweaks to the system, e.g. /etc/fstab
echo "# Device Mountpoint FStype Options Dump Pass#" > $ROOTFSDIR/etc/fstab
echo "/dev/gpt/rootfs / ufs rw,noatime 1 1" >> $ROOTFSDIR/etc/fstab
echo "/dev/gpt/swapfs none swap sw 0 0" >> $ROOTFSDIR/etc/fstab
echo "hostname=qemu" > $ROOTFSDIR/etc/rc.conf
# Add be sure to add them to METALOG
echo "./etc/fstab type=file uname=root gname=wheel mode=0644" >> $ROOTFSDIR/METALOG
echo "./etc/rc.conf type=file uname=root gname=wheel mode=0644" >> $ROOTFSDIR/METALOG
# Create a UFS root filesystem from that directory
cd $ROOTFSDIR
makefs -B little \
-o label=rootfs -o version=2 -o softupdates=1 \
-D -s 6g \
rootfs.ufs METALOG
//Note: specify -s or -f to ensure the filesystem is created with free inodes//
**Create EFI partition**
# Copy the EFI bootloader
setenv EFIDIR $HOME/efistage
mkdir -p $EFIDIR/EFI/BOOT/
cp $ROOTFSDIR/boot/loader.efi $EFIDIR/EFI/BOOT/BOOTRISCV64.EFI
# Create an EFI partition (msdosfs)
makefs -t msdos \
-o fat_type=32 -o sectors_per_cluster=1 -o volume_label=EFISYS \
-s 50m \
efi.part $EFIDIR
**Create Image File**
Now, to combine our root and EFI partitions into a final image file:
mkimg -s gpt -f raw \ # GPT partition scheme
-p efi:=efi.part \
-p freebsd-swap/swapfs::2G \ # Swap partition (optional)
-p freebsd-ufs/rootfs:=rootfs.ufs \
-o riscv.img
''%%riscv.img%%'' is the final output. You may clean up all other temporary objects as you choose.
===== Boot FreeBSD =====
To boot using u-boot, install [[https://www.freshports.org/sysutils/u-boot-qemu-riscv64|sysutils/u-boot-qemu-riscv64]].
qemu-system-riscv64 -machine virt -smp 2 -m 2048 -nographic \
-bios /usr/local/share/opensbi/lp64/generic/firmware/fw_jump.elf \
-kernel /usr/local/share/u-boot/u-boot-qemu-riscv64/u-boot.bin \
-drive file=/path/to/riscv.img,format=raw,id=hd0 \
-device virtio-blk-device,drive=hd0
The %%FreeBSD%% kernel can also be booted directly, skipping the u-boot and ''%%loader(8)%%'' stages. This can be useful for quicker turnaround during kernel development, but is in general less flexible compare to u-boot.
qemu-system-riscv64 -machine virt -smp 2 -m 2048 -nographic \
-bios /path/to/opensbi/fw_jump.elf \
-kernel /path/to/freebsd/kernel \
-drive file=/path/to/riscv.img,format=raw,id=hd0 \
-device virtio-blk-device,drive=hd0
===== Networking =====
There are two main networking backends offered by QEMU, user and tap. User-mode networking requires almost no configuration, but tap based networking offers better performance, and allows the guest to obtain its own IP address on the network.
==== Configure tap(4) (Optional) ====
If using tap(4) for networking (as opposed to user-mode networking), you will need to load the (tun)tap module(s) if not already loaded.
If %%FreeBSD%% >= 13:
sudo kldload if_tuntap
Else:
sudo kldload if_tun if_tap
Configure the network with tap(4):
ifconfig tap0 create up
ifconfig bridge0 create up
ifconfig bridge0 addm em0 addm tap0 # em0 might depend on your ethernet device
==== User Networking ====
Add the following arguments to the QEMU commandline:
-netdev user,id=net0,ipv6=off,hostfwd=tcp::8022-:22 -device virtio-net-device,netdev=net0
This will forward port 8022 on the host to port 22 in the guest, meaning you can connect via ssh(1):
$ ssh -p 8022 root@localhost
==== Tap Networking ====
Add the following arguments to the QEMU commandline.
# ifname points to your tap device of choice
-netdev tap,ifname=tap0,script=no,id=net0 -device virtio-net-device,netdev=net0
===== Tips & Tricks =====
==== Commandline arguments ====
You can specify kernel commandline arguments via QEMU's ''%%-append%%'' option. For example:
-append "-v vfs.root.mountfrom=/dev/vtbd1p3"
The ''%%-v%%'' argument enables verbose boot messages, while the variable assignment instructs the system to attempt to mount root from ''%%/dev/vtbd1p3%%''. These will be ignored if booting with loader(8).