QEMU made easy.
QEMU Basic.
QEMU is a common virtualization tool used to emulate a full system/user application. In this post, we will cover how to set up a basic QEMU full system emulation. In essence, you need two things to boot a full system in QEMU.
- Kernel Image
- Root File-system
Rootfs made easy.
Building a rootfs from scratch can be a daunting task. However, there are tools available that can help you build a rootfs with ease. We can obtain a script named create-image.sh
from here. This script is a part of syzkaller project and is used to create a rootfs for QEMU. The script is well documented and easy to understand. The script uses debootstrap
to create a rootfs. You can install debootstrap
using your package manager.
Downloading nightmare under slow network.
There is a small issue with the script’s configuration. By default, create-image.sh
does not cache anything previously downloaded. If the script is interrupted for any reason, it will download everything again. This can be a problem if you have a slow internet connection. To fix this issue, you can change the following line in the script.
DEBOOTSTRAP_PARAMS="--arch=$DEBARCH --include=$PREINSTALL_PKGS --components=main,contrib,non-free,non-free-firmware --cache-dir=$(pwd)/.cache $RELEASE $DIR"
Kernel made easy.
There are some mythical configuration besides $ARCH_defconfig
that you need if you want to boot smoothly in QEMU. These are the following. These stuff can be found at here.
CONFIG_CONFIGFS_FS=y
CONFIG_SECURITYFS=y
CONFIG_BINFMT_MISC=y
QEMU made easy.
Now that we have a rootfs and kernel image, we can boot the system using QEMU. The following command will boot the system. I use aarch64 as an example. You can change the architecture according to your kernel image.
Note that the kernel cmdline argument
net.ifnames=0
is NOT redundant, otherwise the image will boot into emergency mode.
qemu-system-aarch64 \
-machine virt,virtualization=true,gic-version=3 \
-nographic \
-m size=1024M \
-cpu max \
-smp 2 \
-hda ./bookworm.img \ # change this to your image path
-nic user,model=virtio-net-pci \
-kernel ./linux-6.8.8/arch/arm64/boot/Image \ # change this to your kernel path
--append "console=ttyAMA0 root=/dev/vda rw net.ifnames=0"
Sharing between host and guest.
The following content is taken from here.
To begin with, we need to enable the following kernel configuration in the guest kernel.
CONFIG_9P_FS=y
CONFIG_9P_FS_POSIX_ACL=y
CONFIG_9P_FS_SECURITY=y
CONFIG_NETWORK_FILESYSTEMS=y
CONFIG_NET_9P=y
CONFIG_NET_9P_DEBUG=y
CONFIG_NET_9P_VIRTIO=y
# if you are using aarch64, add the following as well.
CONFIG_PCI=y
CONFIG_PCI_HOST_COMMON=y
CONFIG_PCI_HOST_GENERIC=y
CONFIG_VIRTIO_PCI=y
CONFIG_VIRTIO_BLK=y
CONFIG_VIRTIO_NET=y
We then add the following stuff, telling QEMU to map a host directory into the guest.
# original post says to use security_model=passthrough, but it doesn't work for me.
-virtfs local,path=<host-path>,mount_tag=host0,security_model=mapped-xattr,id=host0
In the guest, we can mount the shared directory using the following command.
mount -t 9p -o trans=virtio,version=9p2000.L host0 <guest-path>
Or you can just add a line in /etc/fstab
to mount the directory automatically.
host0 <guest-path> 9p trans=virtio,version=9p2000.L 0 0