Build A MMIO Booting Debian VM Out Of Cloud Images
by Emile `iMil' Heitor - 2025-01-23
As you might be aware of, I am working on a minimal BSD/UNIX system called smolBSD. It is based on the NetBSD operating system, and its main target is virtual machines, more specifically microvms. This system is capable of fully booting the OS in less than one second using a specially trimmed kernel along with small, specialized root systems.
I was stunned to learn (but am I wrong?) that this work does not seem to have an equivalent, not even in the Linux world. FreeBSD Firecracker support sure permits to boot a kernel is about the same time my NetBSD hacked kernel does, but there’s no work around s slim and task dedicated root filesystem.
For my own needs, I wanted to boot a Linux system the same way I boot smolBSD, using direct kernel boot and MMIO VirtIO disk and network. It turns out it can be achieved out of a Debian cloud image, but it’s not an Out of The Box process…
First fetch a Debian cloud image
$ curl -O -L https://cdimage.debian.org/images/cloud/bookworm/latest/debian-12-genericcloud-amd64.raw
By default, this image does not have a password for any of its users… because it is meant to be configured via cloud-init (seriously guys??). Fortunately, a collection of tools hidden in the libguestfs-tools
package allow to interact with the image.
$ sudo apt install libguestfs-tools
So first up, we want to configure a password for the root user
$ sudo virt-customize --add "debian-12-genericcloud-amd64.raw" --root-password password:debian
The image can be booted directly as a block device, but we can do better, let’s extract the Linux kernel along with the associated initrd
image, again with the help of one of libguestfs-tools
$ sudo virt-copy-out -a debian-12-genericcloud-amd64.raw /boot/vmlinuz-6.1.0-30-cloud-amd64 .
$ sudo virt-copy-out -a debian-12-genericcloud-amd64.raw /boot/initrd.img-6.1.0-30-cloud-amd64 .
We can now directly boot the kernel with the help of QEMU’s -kernel
flag
$ qemu-system-x86_64 -m 1024m -enable-kvm -hda debian-12-genericcloud-amd64.raw -kernel vmlinuz-6.1.0-30-cloud-amd64 -append "root=/dev/sda1 console=ttyS0" -initrd initrd.img-6.1.0-30-cloud-amd64 -display none -serial stdio
But that’s not the endgame, here’s a fully virtualized version, using the QEMU microvm machine type and MMIO capabilities within the Linux kernel
$ qemu-system-x86_64 -M microvm -m 1024m -enable-kvm -kernel vmlinuz-6.1.0-30-cloud-amd64 -append "root=/dev/vda1 console=ttyS0" -initrd initrd.img-6.1.0-30-cloud-amd64 -display none -serial stdio -device virtio-net-device,netdev=net0 -netdev user,id=net0,ipv6=off -device virtio-blk-device,drive=hd0 -drive if=none,file=debian-12-genericcloud-amd64.raw,format=raw,id=hd0
Here we go, that’s surely not a 1 second booting virtual machine, but that will do for our needs.