The problem#
It's annoying to test boot sequences, either of flash drives or your computer. Rebooting every time you want to test a change is slow and loses your place. Which is especially frustrating if you're using a live USB to attempt to repair a broken bootloader and you have to try multiple times. For a bootable flash drive, at least you might have another computer to test it on, making the problem just mildly inconvenient. But what if you didn't have to boot your computer to test the boot sequence?
The solution#
Of course, you have to boot some computer. But it doesn't have to be a
physical one: it can be a virtual machine. While virtual machines
often use virtual hard disks backed by files, they can also use real
disks. And QEMU's -snapshot
flag lets you read
from a real disk without actually writing back to it. All changes are
stored in temporary storage unless you "commit" them, which you do not
want to do for this purpose.
IMPORTANT: Always make sure to use -snapshot
when running QEMU on a
real disk, especially if that disk is in use by the host system. The
following commands also have you set the file permissions so QEMU does
not have write access to the disks to be extra careful.
The following will run a virtual machine booting off a flash drive
(change /dev/sdc
to the appropriate device):
# Grant current user read-only access to flash drive
sudo chgrp "$(id -gn)" /dev/sdc
sudo chmod g=r /dev/sdc
# Boot VM off flash drive
qemu-system-x86_64 -snapshot \
-net none -machine q35 \
-bios /usr/share/ovmf/OVMF.fd \
-cpu host -m 8G -enable-kvm \
/dev/sdc
To instead boot off your machine's internal drive (assuming it is an
NVME SSD with device name /dev/nvme0n1
):
uefivars -i efivarfs -o edk2 \
-I /sys/firmware/efi/efivars -O OVMF_VARS.fd
# Grant current user read-only access to primary SSD
sudo chgrp "$(id -gn)" /dev/nvme0n1
sudo chmod g=r /dev/nvme0n1
# Boot VM off primary SSD
qemu-system-x86_64 -snapshot \
-net none \
-drive file=/dev/nvme0n1,if=none,id=nvm \
-device nvme,serial=deadbeef,drive=nvm \
-machine q35 \
-drive if=pflash,format=raw,unit=0,readonly=on,\
file=/usr/share/OVMF/OVMF_CODE_4M.fd \
-drive if=pflash,format=raw,unit=1,file=OVMF_VARS.fd \
-cpu host -m 8G -enable-kvm
Those commands require QEMU, KVM, and OVMF installed as well as the Python package uefivars. The paths for OVMF are where Debian installed the files on my system, but they may be in a different place or have slightly different filenames on your system.
Note booting the VM may not be instant: that second command takes almost a minute to reach the GRUB menu on my computer.