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 emulators/qemu50 or emulators/qemu-devel.
Also required is the OpenSBI bootloader, which can be installed from the 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 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,if=none \ -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,if=none \ -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).